• Golang的坑


    坑1. 延迟函数参数实时解析

    func main() {
         a()
    }
    func a() {
        i := 1
        defer fmt.Println(i)
        i++
    }

    程序执行的最终结果是 1

    进阶版:

    type X struct {
    	Num int
    }
    
    func main() {
    	i := &X{Num: 2}
    	fmt.Printf("0x0000: %p
    ", i)
    
    	defer fmt.Println("0x0050:", *i)
    	defer fmt.Printf("0x0040: %p
    ", i)
    	defer func() {
    		fmt.Println("0x0032:", i.Num)
    		fmt.Printf("0x0033: %p
    ", i)
    	}()
    
    	defer func(p *X) {
    		fmt.Println("0x0031:", i.Num)
    	}(i)
    	defer fmt.Println("0x0030:", i)
    	i.Num++
    
    	fmt.Println("0x0010:", i.Num)
    	fmt.Printf("0x0011: %p
    ", i)
    
    	i = &X{Num: 99}
    	fmt.Println("0x0021:", i.Num)
    	fmt.Printf("0x0022: %p
    ", i)
    }

     程序执行的最终结果是

    0x0000: 0xc0000a0000
    0x0010: 3
    0x0011: 0xc0000a0000
    0x0021: 99
    0x0022: 0xc0000aa000
    0x0030: &{3}
    0x0031: 99
    0x0032: 99
    0x0033: 0xc0000aa000
    0x0040: 0xc0000a0000
    0x0050: {2}
    

    坑2. 延迟函数在匿名返回值和命名返回值函数中的不同表现

    func main() {
        fmt.Println(a())
        fmt.Println(b())
    }
    
    func a() int {
        var i int
        defer func() {
            i++
        }()
        return i
    }
    
    func b() (i int) {
        defer func() {
        i++
        }()
        return i
    }

    程序执行的最终结果是 0 1

    在a函数中,可以理解成Go自动创建了一个返回值 retValue,相当于执行retValue = i,然后检查是否有defer,如果有则执行,再返回刚才创建的返回值retValue

    在b函数中,由于返回值在方法定义时已经被定义,所以没有创建retValue的过程,i就是retValue,defer对于result的修改也会被直接返回

    坑3.程序退出时延迟函数不会被执行

    func main() {
        fmt.Println("1")
        defer fmt.Println("0")
        os.Exit(0)
    }

    程序执行的最终结果是1

    坑4. 字典的操作不是原子操作

    有并发需求时使用 sync.Map

    坑5, 接口值的返回总是非nil的

    底层的interface实现是有一个类型一个内部值,只有在内部值和类型都未设置时(nil, nil),一个接口的值才为 nil

    func main() {
        err := FindALL()
        if err != nil {
            fmt.Println(1)
        }
        if err.(*MyErr) != nil {
            fmt.Println(2)
        }
    }
    
    type MyErr struct {
    }
    func (m *MyErr) Error() string {
        return ""
    }
    func FindALL() error {
        var p *MyErr
        return p
    }

    坑6. 字符串时注意

    删除字符串首尾时使用 

    strings.TrimPrefix() strings.TrimSuffix()  

    而不是

    strings.TrimLeft() strings.TrimRight()

    TrimLeft 从左开始, 如果发现了不在cutset中的字符, 就从这个点返回  

    坑7 单例时注意

    官方推荐方式为

    var once sync.Once
    once.Do(func() {
    })

    如果同一目录下,要声明两个单例时, once变量不能重复使用

    8

    https://studygolang.com/articles/2915

    注意stop 和 reset

    技巧1: JSON解析不输出

    结构体增加tag可以在结构体的字段为nil时不输出

    `json:"omitempty"`
    

    技巧2: JSON延迟解析

    json.RawMessage
    

    坑8. 原生sql.Open 默认只是检查下链接字符串是不是正确的, 要检查是否连接上用connect 或者 open完了之后ping

    参考链接:

    https://golang.org/doc/faq#atomic_maps

    golang中defer的使用规则

    关于 Go defer 对匿名返回值和命名返回值的不同行为

    Go语言中defer的一些坑

    https://golang.org/doc/faq#nil_error

    Go中error类型的nil值和nil

    https://wrfly.kfd.me/posts/go-trimleft-and-trimprefix/

  • 相关阅读:
    线性回归问题
    聚类:层次聚类
    聚类:(K-means)算法
    神经网络算法
    AutoEventWireup解释
    asp.net中runat="server"的含义
    十步完全理解SQL
    sqlserver中分区函数 partition by的用法
    被忽略却很有用的html标签
    net中使用母版页
  • 原文地址:https://www.cnblogs.com/restful/p/10913818.html
Copyright © 2020-2023  润新知