• Go101细节


    老貘写的Go101,只能说老貘精力真足,这里记录一些细节部分感觉有意思的点。

    switch表达式中的值会默认类型确定,可以自己指定

    package main
    
    func main() {
        switch 123 {
        case int64(123):  // error: 类型不匹配
        case uint32(789): // error: 类型不匹配
        }
    }
    
    
    func main() {
        switch int64(123) {
        case 123:
        case int(123): // error: 类型不匹配
        case int64(123):    
        }
    }

    嵌套的defer可以修改函数的返回值,当然不要这么用。

    func F() (r int) {
        defer func() {
            r = 123
        }()
        return
    }
    
    func main() {
        fmt.Println(F()) // 123
    }

    这里主要是退出协程的细节,这里不会在执行输出Java了,因为在这个它协程的退出后,但是不影响输出c,因为main自己是一个独立的协程。

    package main
    
    import "fmt"
    import "runtime"
    
    func main() {
        c := make(chan int)
        go func() {
            defer func() {
                c <- 1
            }()
            defer fmt.Println("Go")
            func() {
                defer fmt.Println("C")
                runtime.Goexit()
            }()
            fmt.Println("Java")
        }()
        //<-c
        println(<-c)
    }
    
    C
    Go
    1

    一些运算符的优先级

    package main
    
    import "fmt"
    
    type T struct {
        x int
        y *int
    }
    
    func main() {
        var t T
        p := &t.x // <=> p := &(t.x)
        fmt.Printf("%T
    ", p) // *int
    
        *p++ // <=> (*p)++
        *p-- // <=> (*p)--
    
        t.y = p
        a := *t.y // <=> *(t.y)
        fmt.Printf("%T
    ", a) // int
    }

    移位运算时,类型判断取决于右边是否是常量

    package main
    
    func main() {
    }
    
    const M  = 2
    var _ = 1.0 << M // 编译没问题。1.0将被推断为一个int值。
    
    var N = 2
    var _ = 1.0 << N // 编译失败。1.0将被推断为一个float64值。

    var _ = 1.0 << 2 // 编译没问题。1.0将被推断为一个int值。

    两个指针类型的基类共享相同的底层类型,则可以相互转换

    package main
    
    type MyInt int64
    type Ta    *int64
    type Tb    *MyInt
    
    func main() {
        var a Ta
        var b Tb
    
        //a = Ta(b) // error: 直接转换是不允许的。
    
        // 但是间接转换是允许的。
        y := (*MyInt)(b)
        x := (*int64)(y)
        a = x           // 等价于下一行
        a = (*int64)(y) // 等价于下一行
        a = (*int64)((*MyInt)(b))
        _ = a
    }

    两个零值的地址可能相等也可能不相等,其实在栈上是肯定不相等的,在堆上是可能相等的。

    package main
    
    import "fmt"
    
    func main() {
        a := struct{}{}
        b := struct{}{}
        x := struct{}{}
        y := struct{}{}
        m := [10]struct{}{}
        n := [10]struct{}{}
        o := [10]struct{}{}
        p := [10]struct{}{}
    
        fmt.Println(&x, &y, &o, &p)
    
        // 对于标准编译器1.14版本,x、y、o和p将
        // 逃逸到堆上,但是a、b、m和n则开辟在栈上。
    
        fmt.Println(&a == &b) // false
        fmt.Println(&x == &y) // true
        fmt.Println(&a == &x) // false
    
        fmt.Println(&m == &n) // false
        fmt.Println(&o == &p) // true
        fmt.Println(&n == &p) // false
    }

    一个指针类型的基类可以是该指针类型本身,不推荐如此使用。

    package main
    
    func main() {
        type P *P
        var p P
        p = &p
        p = **************p
    }
    package main
    
    func main() {
        type S []S
        type M map[string]M
        type C chan C
        type F func(F) F
    
        s := S{0:nil}
        s[0] = s
        m := M{"Go": nil}
        m["Go"] = m
        c := make(C, 3)
        c <- c; c <- c; c <- c
        var f F
        f = func(F)F {return f}
    
        _ = s[0][0][0][0][0][0][0][0]
        _ = m["Go"]["Go"]["Go"]["Go"]
        <-<-<-c
        f(f(f(f(f))))
    }

    无论一个指针值的类型是定义的还是非定义的,如果它的(指针)类型的基类型为一个结构体类型,则我们可以使用此指针值来选择它所引用着的结构体中的字段。 但是,如果此指针的类型为一个定义的类型,则我们不能使用此指针值来选择它所引用着的结构体中的方法。

    我们总是不能使用二级以上指针来选择结构体字段和方法。这里尤其注意引用方法。这里用指针理解蛮好理解的,可能对于确定类型的一级指针无法引用基类的方法难理解一点,还是方法绑定的问题。

    package main
    
    type T struct {
        x int
    }
    func (T) m(){} // T有一个方法m。
    
    type P *T  // P为一个定义的一级指针。
    type PP *P // PP为一个定义的二级指针。
    
    func main() {
        var t T
        var tp = &t
        var tpp = &tp
        var p P = tp
        var pp PP = &p
        tp.x = 12  // 没问题
        p.x = 34   // 没问题
        pp.x = 56  // error: 类型PP没有名为x的字段或者方法。
        tpp.x = 78 // error: 类型**T没有名为x的字段或者方法。
    
        tp.m()  // 没问题,因为类型*T也有一个m方法。
        p.m()   // error: 类型P没有名为m的字段或者方法。
        pp.m()  // error: 类型PP没有名为m的字段或者方法。
        tpp.m() // error: 类型**T没有名为m的字段或者方法。
    }

    对于映射我们一般不需要在取item处进行大量的判断,因为不论你的映射是否为空都无所谓,所以个人建议从入口和出口控制而不是中间过程。

    func Foo1(m map[string]int) int {
        if m != nil {
            return m["foo"]
        }
        return 0
    }
    
    func Foo2(m map[string]int) int {
        return m["foo"]
    }

    不整理了,进度过慢。

    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    直击微软第九频道著名主持Robert Green 对话一站式示例代码库大老板梁梅女士
    微软发布中文版一站式示例代码浏览器
    每日一例,练就编程高手
    微软发布Visual Studio 2012 示例代码浏览器
    微软发布Sample Browser for Windows 8版:5000示例代码,"触手可及"
    arthas使用总结
    前端如何生成二维码
    golang的helloworld以及nonmain package的troubleshooting
    监控文件的网页工具
    postfix + courierimap + squirrelMail 邮件服务器
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12800820.html
Copyright © 2020-2023  润新知