美文网首页
Go == 用法十二则

Go == 用法十二则

作者: Robin92 | 来源:发表于2020-04-17 20:28 被阅读0次

规则一:两个操作数类型必须相同!必须相同!必须相同!

否则,编译时就会报错。Go 的类型系统非常严格,没有隐式转换,所以一个 int 与 int32 是无法比较的,int 与自定义的 type myint int 也是无法比较的。

规则二:浮点类型运算有误差,所以运算后的比较可能有问题

这是计算机语言普遍有的问题, 即 “0.1 + 0.2 == 0.3" 不成立。所以尽量不要比较浮点类型,要比较时可以取差再与一个接近 0 的浮点数(如 1e-9)比较。

规则三:数组的长度是类型的一部分,不同长度的数组,不能比较

注意,是 不能 比较,是会在编译时发生错误。因为类型不同。

规则四:等长数组的比较按元素逐个比较

数组的比较是按元素逐个比较的,顺序不同的数组不相等。(数组没 > < 的比较)

规则五:引用类型除 slice 和 map 外(即包含指针和 channel)比较的是地址,而不是比较实际值。


type A struct {
    a int
}

func main() {
    b := &A{1}
    c := &A{1}

    d := A{1}
    e := &d
    f := &d
    fmt.Println(c == b) // false
    fmt.Println(f == e) // true
}

规则六: slice 和 map 只允许与 nil 比较,与其他比较时编译错误

为什么这样规定呢,因为切片是引用类型,它可以间接指向自己

    a := []int{1, 2, 3, 4, 5}
    a = a[2:3]                     // 指向自己
    fmt.Println(a, len(a), cap(a)) // [3] 1 3,cap 是到数组结束

切片一步递归赋值时直接爆栈;map 亦然;数组OK。

    a := [2]interface{}{0, 1} // 数组
    a[0] = a                  // 可以递归赋值
    fmt.Println(a)            // [[0 1] 1]

    b := []interface{}{0, 1} // 切片
    b[0] = b                 // 递归赋值时
    fmt.Println(b)           // fatal error: stack overflow 爆栈

    d := map[int]interface{}{1: 2}
    d[1] = d
    fmt.Println(d)
    // runtime: goroutine stack exceeds 1000000000-byte limit
    // fatal error: stack overflow
    // 一样爆栈

上面爆栈是在 fmt.Println() 处爆的,而不是递归赋值的位置。
数组不爆栈是因为数组赋值是值拷贝。切片和 map 是改变引用,在输出的时候会递归输出导致爆栈。

规则七:接口类型比较的是基本类型与动态值

    var a interface{} = 1
    var b interface{} = 1
    var c interface{} = 2
    var d interface{} = "a"

    fmt.Println(a == b) // true,类型相同,值相同
    fmt.Println(a == c) // false,类型相同,值不同
    fmt.Println(a == d) // false,类型不同

    var e interface{} = myint(1) // type myint int
    fmt.Println(a == e)          // false,类型不同,值量相同

规则八:接口类型的基本类型不可比较时,强行比较发生 panic

    var a interface{} = []int{2}
    var b interface{} = []int{2}
    fmt.Println(a == b) // panic: runtime error: comparing uncomparable type []int

规则九:接口值的比较只要相互可以转化就可以比较

    var f *os.File             // f
    var g *os.File             // g 是另一个变量
    var f_r io.Reader = f      //
    var f_rc io.ReadCloser = f //
    var g_rc io.ReadCloser = g //
    fmt.Println(f_r == f_rc)   // 可以比较,true
    fmt.Println(f_rc == g_rc)  // 可以比较,true,这个尚不清楚

规则十:任何含有不可比较类型的类型是不可比较的

如,当结构体中含有切片时、数组元素中含有切片时、指针指向切片时,他们都不可以比较,map 亦然。编译报错

规则十一:zero-width struct 的指针比较不保证比较的正确性

zero-width struct 是没有任何属性的结构体,即 struct{}{}。他们的指针比较可能为 true,也可能是 false。
alias 之后如 type People struct{} 也一样。

规则十二:用 reflect.DeepEqual 比较任何值

包括切片、map、Func,以及包含这些类型属性的结构体。


相关文章

网友评论

      本文标题:Go == 用法十二则

      本文链接:https://www.haomeiwen.com/subject/hxhuvhtx.html