措不及防的golang bug 总结(继续更新)

  1. 关于for的陷阱:

// forrange 会将迭代对象做一次值拷贝,会影响数组(值传递)的修改
func testforarr() {
    arr := [3]int{1, 2, 3}
    for i, v := range arr {
        if i == 0 {
            arr[i] = 100
        }
        fmt.Println(i, v)
    }
    // output:0,1 1,2 2,3

    // for i, v := range &arr { //迭代数组地址
    // for i, v := range arr[:] {    //切片为引用类型
}

//map 遍历无序
func testformap() {
    m := map[string]int{
        "a": 1,
        "b": 2,
        "c": 3,
    }
    for k, v := range m {
        fmt.Println(k, v)
    }
    // 遍历map无序,杜绝一切迭代 map 顺序相关的逻辑(java笑哭),至于原因,照官方说法是早期golang开发人员大量代码基于map遍历的顺序,影响移植性……
}
// 闭包:在必要情况下,可用值拷贝将参数传入闭包
func testforclosure() {
    for i := 0; i < 5; i++ {
        //1 output:5 5 5 5 5
        defer func() {
            fmt.Println("Defer", i)
        }()
    }
    for i := 0; i < 5; i++ {

        //2 output:4 3 2 1 0
        a := i
        defer func() {
            fmt.Println("Defer", a)
        }()
    }
    for i := 0; i < 5; i++ {

        //3 output:4 3 2 1 0
        defer func(i int) {
            fmt.Println("Defer", i)
        }(i)
    }
    // other:多个 defer 语句逆序执行

}
  1. 不能取地址的几种情况:

func testAddr() {
    // 不能取地址的情况:
    // 1.constant:地址传出去会导致常量被修改
    // const a int = 10
    // b:=&a    error

    // 2.临时变量(需要先存下来)
    // b := &f()    error

    // b:=f()
    // c:=&b    true

    // 3.map的索引(map括容时会修改地址,导致括容前的地址无效)
    // m := map[string]int{
    //     "a": 10,
    // }
    // b := &m["a"]    error

    // 4 interface 向上转型的过程中会做一次值拷贝
    p := Person{}
    // var s Shower = p // error 此处拷贝结构体 Person,而Person 的方法集中并没有 Show(),因此向上转型失败

    var s Shower = &p // 此处拷贝的地址
    Show(s)

    // 5 assert
    var v any = Person{}
    p = v.(Person)
    p.Show()

    //v.(Person).Show()    //无法对 v.(Person) 取地址
}

func f() int {
    var a int = 10
    b := a
    return b
}
  1. 指针接收者类型的接口实现

type Person struct{}

type Shower interface {
    Show()
}

// 接收者为指针类型,值类型Person的方法集中没有 Show()
func (p *Person) Show() {}

func Show(s Shower) {
}

func UnitMain() {
    p := Person{}
    // 指针类型的方法集 包含指针类型方法 和 值类型方法,因此这里是可以调用的
    p.Show()
    Show(&p)
    //Show(p) //error:Person 未实现接口

    // //func (p Person) Show() {}
    // p := &Person{}
    // p1 := Person{}
    // Show(p)  //true
    // Show(p1) // true

}

你可能感兴趣的:(go,那些年写过的Bug,golang,bug)