zoukankan      html  css  js  c++  java
  • golang(3):strings和strconv使用 & 时间和日期类型 & 指针类型 & 流程控制 & 函数

    strings和strconv使用

    1. strings.HasPrefix(s string, prefix string) bool// 判断字符串s是否以prefix开头 。
    
    2. strings.HasSuffix(s string, suffix string) bool// 判断字符串s是否以suffix结尾。
    
    3. strings.Index(s string, str string) int// 判断str在s中首次出现的位置,如果没有出现,则返回-1
    
    4. strings.LastIndex(s string, str string) int// 判断str在s中最后出现的位置,如果没有出现,则返回-1
    
    5. strings.Replace(str string, old string, new string, n int):    // 字符串替换; 如果 n<0,表示全部替换
    
    6. strings.Count(str string, substr string)int// 字符串计数
    
    7. strings.Repeat(str string, count int)string// 重复count次str
    
    8. strings.ToLower(str string)string// 转为小写
    
    9. strings.ToUpper(str string)string// 转为大写
    
    10. strings.TrimSpace(str string):                // 去掉字符串首尾空白字符;
     也会去掉
        strings.Trim(str string, cut string):        // 去掉字符串首尾cut字符
            func Trim(s string, cutset string) string
                ---> 去掉字符串s中首部以及尾部与字符串cutset中每个相匹配的字符,如:
                ---> s="hello yes",cutset="he",那么s的结果为:"llo yes"
        strings.TrimLeft(str string, cut string):    // 去掉字符串首cut字符
        strings.TrimRight(str string, cut string):    // 去掉字符串尾cut字符
    
    11. strings.Fields(str string):        // 返回str空格分隔的所有子串的slice
        strings.Split(str string, split string):        // 返回str split分隔的所有子串的slice
    
    12. strings.Join(s1 []string, sep string):        // 用sep把s1中的所有元素链接起来
    
    13. strconv.Itoa(i int):        // 把一个整数i转成字符串 <---> fmt.Sprintf("%d",str)
    
    14. strconv.Atoi(str string)(int, error):    // 把一个字符串转成整数

    15. strings.Contains(s string, substr string) bool: // 是否包含

    参考链接: https://www.cnblogs.com/action-go/p/11560190.html

    示例代码1:

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func urlProcess(url string) string {
        result := strings.HasPrefix(url,"http://")    // strings.HasPrefix(变量,匹配内容) 返回一个 bool 值
        if !result{
        url = fmt.Sprintf("http://%s",url)
        }
        return url
    }
    
    func pathProcess(path string) string {
        result := strings.HasSuffix(path,"/")   // strings.HasSuffix(变量,匹配内容) 返回一个 bool 值
        if !result{
            path = fmt.Sprintf("%s/",path)
        }
        return path
    }
    
    func main (){
        var (
        url string
        path string
        )
    
        fmt.Scanf("%s%s",&url,&path)
        url = urlProcess(url)
        path = pathProcess(path)
    
        fmt.Println(url)
        fmt.Println(path)
    
    }
    
    // 运行结果:
    [root@NEO example01_string01]# go run main/main.go 
    10.0.0.8/login f:/learning  
    http://10.0.0.8/login
    f:/learning/
    [root@NEO example01_string01]# 

    # 示例代码2:

    package main
    
    import (
        "fmt"
        "strings"
        "strconv"
    )
    
    func main(){
        str := "  hello world abc    
    "
    
        result := strings.Replace(str,"abc","neo",1)    // 字符串替换
        fmt.Println("Replace:",result)
    
        count := strings.Count(str,"o")    // 字符串计数
        fmt.Println("Count:",count)
    
        result = strings.Repeat(str,3)    // 把字符串重复几次、拼接到一起
        fmt.Println("Repeat:",result)
    
        result = strings.ToLower(str)    // 变成小写
        fmt.Println("ToLower:",result)
    
        result = strings.ToUpper(str)    // 变成大写
        fmt.Println("ToUpper:",result)
    
        result = strings.TrimSpace(str)     // 去掉字符串首尾空白字符;
     也会去掉
        fmt.Println("TrimSpace:",result)
    
        result = strings.Trim(str," 
    
    ")    // 去掉字符串首尾 cutset 字符
        fmt.Println("Trim:",result)
    
        result = strings.TrimLeft(str," 
    
    ")  // 去掉左侧
        fmt.Println("TrimLeft:",result)
    
        result = strings.TrimRight(str," 
    
    ")  // 去掉右侧
        fmt.Println("TrimRight:",result)
    
        splitResult := strings.Fields(str)    // 以空格为分隔符切割字符串,返回数组
        for i := 0; i<len(splitResult);i++ {
        fmt.Printf("fieldsResult[%d]=%s
    ",i,splitResult[i])
        }
    
        splitResult = strings.Split(str,"o")  // 以"o"为分隔符切割字符串,返回数组
        for i := 0; i<len(splitResult);i++ {
            fmt.Printf("splitResult[%d]=%s
    ",i,splitResult[i])
        }
       
        str2 := strings.Join(splitResult,"o")    // 拼接字符串
        fmt.Println("Join:",str2)
    
        str2 = strconv.Itoa(100)    // 数字转字符串
        fmt.Println("Itoa:",str2)
    
        num,err := strconv.Atoi(str2) // 字符串转数字;有两个返回值
    
        if err != nil {
        fmt.Println("can not convert to int",err)
        return
        }
        fmt.Println("Atoi:",num)
    
    }
    
    
    // 编译后执行结果如下:
    [root@NEO project]# go build -o bin/example01_string02 go_dev/day03/example01_string02/main
    [root@NEO project]# bin/example01_string02 
    Replace:   hello world neo    
    
    Count: 2
    Repeat:   hello world abc    
      hello world abc    
      hello world abc    
    
    ToLower:   hello world abc    
    
    ToUpper:   HELLO WORLD ABC    
    
    TrimSpace: hello world abc
    Trim: hello world abc
    TrimLeft: hello world abc    
    
    TrimRight:   hello world abc
    fieldsResult[0]=hello
    fieldsResult[1]=world
    fieldsResult[2]=abc
    splitResult[0]=  hell
    splitResult[1]= w
    splitResult[2]=rld abc    
    
    Join:   hello world abc    
    
    Itoa: 100
    Atoi: 100
    [root@NEO project]# 

    Go中的时间和日期类型

    1. time包
    2. time.Time类型,用来表示时间
    3. 获取当前时间, now := time.Now()
    4. time.Now().Day(),time.Now().Minute(),time.Now().Month(),time.Now().Year()
    5. 格式化,fmt.Printf(“%02d/%02d/%02d %02d:%02d:%02d”, now.Year()…)  
        // %02d : 02 modified %d (an adverb !) to pad the result with zeros to exactly 8 digits. (用0把结果填充到2位数字)
    6. time.Duration用来表示纳秒 7. 一些常量: const ( Nanosecond Duration = 1 * Nanosecond Microsecond = 1000 * Nanosecond Millisecond = 1000 * Microsecond Second = 1000 * Millisecond Minute = 60 * Second Hour = 60 * Minute ) 8. 格式化: now := time.Now() fmt.Println(now.Format(“02/1/2006 15:04:05”)) fmt.Println(now.Format(“2006/1/02 15:04”)) fmt.Println(now.Format(“2006/1/02”))

    示例3:
    写一个程序,获取当前时间,并格式化成 2017/06/15 08:05:00 形式
    写一个程序,统计一段代码的执行耗时,单位精确到微秒。

    // 示例代码如下:
    package main
    
    import (
        "fmt"
        "time"
    )
    
    func test_runtime(){
        time.Sleep(time.Millisecond * 100)      // 停 100 毫秒
    }
    
    func main (){
        now := time.Now()
        // 方式一
        fmt.Printf("%02d/%02d/%02d %02d/%02d/%02d
    ",now.Year(),now.Month(),now.Day(),now.Hour(),now.Minute(),now.Second())
    
        // 方式二: time 自带一个 Format() 函数
        fmt.Println(now.Format("2006-01-02 15:04:05"))
    
        start := time.Now().UnixNano()    // 获取当前时间戳(纳秒级)
        test_runtime()
        end := time.Now().UnixNano()
    
        fmt.Printf("runtime:%d us
    ",(end-start)/1000)
    }
    
    // 运行结果如下:
    [root@NEO example01_string03]# go run main/main.go 
    2019/07/19 00/11/35
    2019-07-19 00:11:35
    runtime:100255 us
    [root@NEO example01_string03]#

     

    指针类型

    1. 普通类型,变量存的就是值,也叫值类型
    2. 获取变量的地址,用&,比如: var a int, 获取a的地址:&a
    3. 指针类型,变量存的是一个地址,这个地址存的才是值
    4. 获取指针类型所指向的值,使用:*,比如:var *p int, 使用*p获取p指向的值

    示例4:
    写一个程序,获取一个变量的地址,并打印到终端。
    写一个函数,传入一个int类型的指针,并在函数中修改所指向的值。在main函数中调用这个函数,并把修改前后的值打印到终端,观察结果

    // 示例代码如下:
    package main
    
    import (
        "fmt"
    )
    
    func pointer_val(p *int){    // 该函数的参数p需要传入一个地址
        *p = 2    // 修改 指针p 指向的值
    }
    
    func main(){
        str := "hello world"
        fmt.Println("addr=",&str)
    
        num := 1
        var p *int       // 声明一个 int 类型的指针;p 里面存的是地址
        p = &num   // 给指针类型的变量赋值时,需要赋值一个地址(&变量);取出指针 p 所指向的值 ---> *p
        fmt.Println("p=",p)
        fmt.Println("pointer_val_before=",*p)
        pointer_val(p)    // p 参数是一个地址
        fmt.Println("pointer_val_after=",*p)
    }
    
    // 运行结果如下:
    [root@NEO example03_pointer01]# go run main/main.go
    addr= 0xc0000101e0
    p= 0xc0000120b0
    pointer_val_before= 1
    pointer_val_after= 2
    [root@NEO example03_pointer01]# 

    流程控制

    # if语句:
    // 1、
    if condition1 {
    }
    
    // 2、
    if condition1 {
        
    } else {
    
    }
    
    // 3、
    if condition1 {
        
    } else if condition2 {
    
    } else if condition3 {
    } else {
    }
    
    
    # switch case 语句
    // 语法:
    switch var {     // var 就变量
    case var1:
    case var2:
    case var3:
    default:
    }
    
    // 形式1:
    var i = 0
    switch i {
    case 0:
        fallthrough        // fallthrough 具有 穿透 的作用
    case 1:
        fmt.Println(“1”)    // go  switch 的 case 后不需要加 break
    case 2,3,4,5:
        fmt.Println(“2”)
    default:
         fmt.Println(“def”)
    }
    
    // 形式2:
    var i = 0
    switch {
    case i > 0 && i < 10:
        fmt.Println(“i > 0 and i < 10”)
    case i > 10 && i < 20:
        fmt.Println(“i > 10 and i < 20”)
    default:
        fmt.Println(“def”)
    }

    示例4:猜数字,写一个程序,随机生成一个0到100的整数n,然后用户在终端,输入数字,如果和n相等,则提示用户猜对了。如果不相等,则提示用户,大于或小于n。

    // 示例代码:
    package main
    
    import (
        "fmt"
        "math/rand"
    )
    
    func main(){
       var n int
       n = rand.Intn(100)    // 生成随机数
    
       for {
        flag := false
        var input int
        fmt.Scanf("%d
    ",&input)   // %d
     --> 以 换行作为分隔符
    
        switch {
        case input == n:
            fmt.Println("you are right")
            flag = true
        case input > n:
            fmt.Println("bigger")
        default:
            fmt.Println("smaller")
        }
        if flag {
            break
        }    
       }
    
    } 

    for 语句

    // 方式一:
    for 初始化语句; 条件判断; 变量修改 {
    
    }
    
    // 方式二:
    for  条件 {
    }
    
    // 方式三:for range 语句 --> 用来遍历数组、slice、map、chan
    str := "hello world,中国"
    for i, v := range str {        // i表示下标, v 表示值
        fmt.Printf("index[%d] val[%c] len[%d]
    ", i, v, len([]byte(string(v))))        // len([]byte(string(v))) --> 表示字符的长度
    }
    
    // 方式四:
    str := “hello world,中国”
    for i, v := range str {
        if i > 2 {
             continue
        }
        if (i > 3) {
             break
        }
        fmt.Printf(“index[%d] val[%c] len[%d]
    ”, i, v, len([]byte(string(v))))
    }
    
    // 方式五:goto 和 label 语句
    // label语句1:
    package main
    import "fmt"
    func main() {
    LABEL1:            // label语法 ---> 字符:
        for i := 0; i <= 5; i++ {
            for j := 0; j <= 5; j++ {
                if j == 4 {
                    continue LABEL1        // 会跳转到 LABEL1 处继续执行 
                }
                fmt.Printf("i is: %d, and j is: %d
    ", i, j)
            }
        }
    }
    
    // goto label 语句2:
    package main
    
    func main() {
        i := 0
    HERE:
        print(i)
        i++
        if i == 5 {
            return
        }
        goto HERE    // 会跳转到 HERE 处继续执行 ; 此 goto label 实现了一个 for 循环 (只能在同一个函数中跳转)
    }

    示例5:写一个程序,在终端打印如下图形
    A
    AA
    AAA
    AAAA
    AAAAA

    // 示例代码如下:
    package main
    
    import (
        "fmt"
    )
    
    func print(n int) {
    
        for i := 0; i < n; i++ {
            for j := 0; j < i; j++ {
                fmt.Printf("A")
            }
            fmt.Println()
        }
    }
    
    func main() {
        print(5)
    }

    示例6:(上述的方式三)

    // 示例代码:
    package main
    
    import "fmt"
    
    func main() {
        str := "hello world,中国"
        for i, v := range str { // i表示下标, v 表示值
            fmt.Printf("index[%d] val[%c] len[%d]
    ", i, v, len([]byte(string(v)))) // len([]byte(string(v))) --> 表示字符的度
        }
    }
    
    // 运行结果如下:
    [root@NEO example04_for01]# go run main/main.go 
    index[0] val[h] len[1]
    index[1] val[e] len[1]
    index[2] val[l] len[1]
    index[3] val[l] len[1]
    index[4] val[o] len[1]
    index[5] val[ ] len[1]
    index[6] val[w] len[1]
    index[7] val[o] len[1]
    index[8] val[r] len[1]
    index[9] val[l] len[1]
    index[10] val[d] len[1]
    index[11] val[,] len[1]
    index[12] val[中] len[3]
    index[15] val[国] len[3]
    [root@NEO example04_for01]#

    函数

    golang函数特点:
    // a. 不支持重载,一个包不能有两个名字一样的函数
    // b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量
    // c. 匿名函数
    // d. 多返回值

    示例7:自定义一种函数类型,作为参数传入另一个函数的参数

    package main
    
    import "fmt"
    
    type calc_func func(int, int) int    // type --> 自定义一种类型 calc_func:calc_func 是函数类型,该类型有两个参数均为 int,返回值也是 int
    
    func add(a int, b int) int {
        return a + b
    }
    
    func operator(op calc_func,a int, b int) int {    // op 参数为自定义的 函数类型;函数当作参数传给另一个函数
        return op(a,b)
    }
    
    func main(){
        c := add
        fmt.Println(c)    // c 是函数 add 的内存地址
        sum := operator(c,100,200)    
        fmt.Println(sum)
    }
    
    // 运行结果如下:
    [root@NEO example05_func01]# go run main/main.go
    0x487170
    300
    [root@NEO example05_func01]#

    函数参数传递方式:

    1). 值传递
    2). 引用传递
    注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
    注意2:map、slice、chan、指针、interface默认以引用的方式传递

    函数命名返回值的名字,如下:

    func add(a, b int) (c int) {    // c 就是返回值
        c = a + b
        return
    }
    
    func calc(a, b int) (sum int, avg int) {
        sum = a + b
        avg = (a +b)/2
        return
    }

    _ 标识符,用来忽略返回值,如下:

    func calc(a, b int) (sum int, avg int) {
        sum = a + b
        avg = (a +b)/2
        return
    }
    func main() {
        sum, _ := calc(100, 200)
    }

    函数的可变参数,如下:

    func add(arg…int) int {        // 0个或多个参数
    }
    
    func add(a int, arg…int) int {        // 1个或多个参数
    }
    
    func add(a int, b int, arg…int) int {        // 2个或多个参数
    }
    
    // 注意:其中arg是一个slice(切片,可理解成数组/列表),我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数

    示例8:
    写一个函数add,支持1个或多个int相加,并返回相加结果
    写一个函数concat,支持1个或多个string相拼接,并返回结果

    // 示例代码如下:
    package main
    
    import "fmt"
    
    func add(a int,arg...int) (sum int){
        sum += a
        for i := 0; i < len(arg); i++{
        sum += arg[i]
        }
        return
    }
    
    func concat(s string,arg...string)(result string){
        result += s
        for i := 0; i < len(arg); i++{
            result += arg[i]
        }
        return 
    }
    
    func main(){
        sum := add(1,2)
        fmt.Println(sum)
        sum = add(1,2,3)
        fmt.Println(sum)
    
        result := concat("hello"," world")
        fmt.Println(result)
        result = concat("hello"," world"," neo")
        fmt.Println(result)
    }
    
    // 运行结果如下:
    [root@NEO example05_func02]# go run main/main.go
    3
    6
    hello world
    hello world neo
    [root@NEO example05_func02]# 

    函数 defer:

    // 1. 当函数返回时,执行defer语句。因此,可以用来做资源清理
    // 2. 多个defer语句,按先进后出的方式执行 (栈)
    // 3. defer语句中的变量,在defer声明时就决定了。

    示例代码:

    package main
    
    import "fmt"
    
    func a(){
        i := 0
        defer fmt.Println("func a defer",i)   // 执行这个声明的时候,i 的值已经确实为0,此时语句还没有执行,该语句是在函数返的时候才执行
        i++
        fmt.Println("func a",i)    // 先执行这行代码的 Println,再执行 defer 中的 Println
    }
    
    func f(){
        for i := 0; i < 3; i++ {
        defer fmt.Println("func f defer",i)    // 先执行后面的 defer 语句
        }
    }
    
    func main(){
        a()
        f()
    }
    
    // 运行结果如下:
    [root@NEO example05_defer]# go run main/main.go
    func a 1
    func a defer 0
    func f defer 2
    func f defer 1
    func f defer 0
    [root@NEO example05_defer]#
    
    
    // defer用途(伪代码):
    // 1. 关闭文件句柄
    
    func read() {
        //文件操作
        file := open(filename)
        defer file.Close()
    }
    
    // 2. 锁资源释放
    func read() {
        mc.Lock()
        defer mc.Unlock()
    }
    
    // 3. 数据库连接释放
    func read() {
        conn := openDatabase()
        defer conn.Close()
    }

    示例题:

    1. 编写程序,在终端输出九九乘法表。

    // 示例代码:
    package main
    
    import "fmt"
    
    func multi() {
        for i := 1; i <= 9; i++{
        for j :=1; j<=i; j++ {
            fmt.Printf("%d*%d=%d ",j,i,i*j)
        }
        fmt.Println()
        }
    }
    
    func main(){
        multi()
    }

    2. 一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3。编程找出1000以内的所有完数。

    package main
    
    import "fmt"
    
    func perfect(n int) bool {
        var sum int
        for i :=1; i < n; i++{
        if n%i == 0 {
            sum += i    // 把该数的所有因子加起来
        } 
        }
       return n == sum
    }
    
    func process(n int){
        for i := 1; i <= n; i++{
            if perfect(i){
                fmt.Println(i)
            }
        }
    }
    
    func main(){
        var n int
        fmt.Scanf("%d",&n)
    
        process(n)
    }

    3. 输入一个字符串,判断其是否为回文。回文字符串是指从左到右读和从右到左读完全相同的字符串。

    // 示例代码:
    package main
    
    import "fmt"
    
    func process(s string) bool {
        for i := 0; i < len(s)/2; i++{  // 从字符串的两边向中间靠拢
        if s[i] != s[len(s)-1-i]{
            return false
        }
        }
        return true
    }
    
    func main(){
        var s string
        fmt.Scanf("%s
    ",&s)
    
        result := process(s)
        if result {
        fmt.Printf("%s is huiwen
    ",s)
        } else {
        fmt.Printf("%s not huiwen
    ",s)
        }
    }

    4. 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。

    package main
    
    import (
        "fmt"
        "bufio"
        "os"
    )
    
    func count(s string) (charCount, spaceCount, numCount, otherCount int){
        t := []rune(s)  // 转换类型
    
        for _,v := range t {
        switch {
            case v >= 'A' && v <= 'z':      // 比较是在 ASCII 中的位置数字; byte 型的只能用单引号
            charCount++
            case v == ' ':
            spaceCount++
            case v >= '0' && v <= '9':
            numCount++
            default:
            otherCount++
        }
        }
        return   
    }
    
    func main (){
        reader := bufio.NewReader(os.Stdin)      // bufio.NewReader() 实例化一个对象;os.Stdin 标准输入
        result, _, err := reader.ReadLine()    // 从终端读取输入;返回的第一个参数 (result) 是 []byte
        if err != nil {
        fmt.Println("Read from console err:",err)
        return
        }
    
        fmt.Println(result)
    
        cc, sc, nc, oc := count(string(result))    // 先把 result 转换成 string 类型
        fmt.Printf("word count:%d
     space count:%d
     number count:%d
     others count:%d
    ",cc,sc,nc,oc)
    }
    
    // byte 等同于int8,常用来处理ascii字符
    // rune 等同于int32,常用来处理unicode或utf-8字符
    
    // 运行结果如下:
    [root@NEO example06_count]# go run main/main.go
    hello 123-=
    [104 101 108 108 111 32 49 50 51 45 61]
    word count:5
     space count:1
     number count:3
     others count:2
    [root@NEO example06_count]# 

    5. 计算两个大数相加的和,这两个大数会超过int64的表示范围.

    package main
    
    import (
        "fmt"
    )
    
    func fillZero(s string, n int)string{
        var res string = s
        for i:=1; i<=n; i++{
        res = fmt.Sprintf("%c%s",'0',res)
        }
        return res
    }
    
    func plus(a string, b string) string {
        var index,carry,length int       // index 表示从右开始的个数; carry 表示进位(相加满十进一);length 表示两个数字字符长度
        var str_plus string
    
    
        // 长度小的在前面填充 0
        len1 := len(a)
        len2 := len(b)
    
        if (len1==0 && len2==0){
        return "0"
        }
    
        switch {
        case len1 > len2:
            n := len1 - len2
            res := fillZero(b,n)
            b = res
            length = len1
        case len1 < len2:
            n := len2 - len1
                res := fillZero(a,n)
                a = res    
            length = len2
        default:
            length = len1
        }
    
        // 各位相加    
        for (index <= length-1) {
        byte_a := a[length-1-index] - '0'    // 数字对应的字符 减去 '0' 字符,就是该数字的值;uint8 类型
        byte_b := b[length-1-index] - '0'
    
        sum := int(byte_a) + int(byte_b) + carry
    
        if sum >= 10 {
            carry = 1
        } else {
            carry = 0
        }
        
         byte_new := (sum % 10) + '0'
        str_plus = fmt.Sprintf("%c%s",byte_new,str_plus)
        index++
        }
        if carry == 1{
        str_plus = fmt.Sprintf("1%s",str_plus)
        }
        return str_plus
    }
    
    func main(){
        var a, b string
        fmt.Scanf("%s %s
    ",&a, &b)
    
        res_plus := plus(a,b)
        fmt.Println(res_plus)
    }
  • 相关阅读:
    setsockopt()使用方法(參数具体说明)
    Hadoop 2.4.0全然分布式平台搭建、配置、安装
    对称加密与非对称加密
    学习模式----观察者模式(3)
    Java实现 蓝桥杯VIP 算法训练 特殊的数字四十
    Java实现 蓝桥杯VIP 算法训练 特殊的数字四十
    Java实现 蓝桥杯VIP 算法训练 特殊的数字四十
    Java实现 蓝桥杯VIP 算法训练 s01串
    Java实现 蓝桥杯VIP 算法训练 s01串
    Java实现 蓝桥杯VIP 算法训练 s01串
  • 原文地址:https://www.cnblogs.com/neozheng/p/11198549.html
Copyright © 2011-2022 走看看