• Go语言中的零值坑记


    原文链接:http://www.zhoubotong.site/post/45.html

    开箱即用

    什么叫开箱即用呢?因为Go语言的零值让程序变得更简单了,有些场景我们不需要显示初始化就可以直接用,举几个例子:

    切片,他的零值是nil,即使不用make进行初始化也是可以直接使用的,例如:

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        var s []string
    
        s = append(s, "love")
        s = append(s, "游戏")
        fmt.Println(strings.Join(s, " ")) // love 游戏
    }
    

    但是零值也并不是万能的,零值切片不能直接进行赋值操作:

        var s []string
        s[0] = "love 游戏"
    

    这样的程序就报错了。

    • 方法接收者的归纳:利用零值可用的特性,我们配合空结构体的方法接受者特性,可以将方法组合起来,在业务代码中便于后续扩展和维护:

      package main
      
      import (
          "fmt"
      )
      
      type T struct{}
      
      func (t *T) Run() {
          fmt.Println("love 游戏")
      }
      
      func main() {
          var t T
          t.Run()
      }  

     我在一些开源项目中看到很多地方都这样使用了,这样的代码最结构化。

    零值并不是万能

    Go语言零值的设计大大便利了开发者,但是零值并不是万能的,有些场景下零值是不可以直接使用的:

    • 未显示初始化的切片、map,他们可以直接操作,但是不能写入数据,否则会引发程序panic:

      func main() {
          var s []string
          s[0] = "周伯通" // panic:runtime error: index out of range [0] with length 0
          var m map[string]bool
          m["love"] = true // panic:assignment to entry in nil map
          fmt.Println(s, m)  
      }
      

      这两种写法使用都是错误的。  

    零值的指针

    • 零值的指针就是指向nil的指针,无法直接进行运算,因为是没有无内容的地址:

      func main() {
          var p *uint32
          *p++
          fmt.Println(p) //panic: runtime error: invalid memory address or nil pointer dereference
      }
      

      改成这样才可以

      package main
      
      import (
          "fmt"
      )
      
      func main() {
          var p *uint64
          a := uint64(0)
          p = &a
          *p++
          fmt.Println(*p) // 1
      }   

     

      

    零值的error类型

    error内置接口类型是表示错误条件的常规接口,nil值表示没有错误,所以调用Error方法时类型error不能是零值,否则会引发panic

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        res := response()
        fmt.Println(res.Error()) //panic: runtime error: invalid memory address or nil pointer dereference
    }
    
    func response() error {
        return nil
    }
    

    闭包中的nil函数

    在日常开发中我们会使用到闭包,但是这其中也隐藏了一个问题,如果我们函数忘记初始化了,那么就会引发panic

    package main
    
    var fun func(a, b, c int)
    
    func main() {
        fun(1, 2, 3) // panic: runtime error: invalid memory address or nil pointer dereference
    }
    

    怎么解决呢?可以使用带参数闭包或者不带参数的闭包,以下作为参考示例:

    package main
    
    import "fmt"
    
    func main() {
        //先调用闭包外面的方法传给变量
        add_func := addNumber(1, 2)
        //再调用里面的方法,因为有了i++ 同一个内存地址 在一次编译中i的值会迭代加1
        fmt.Println(add_func(1, 1)) //1  3  2
        fmt.Println(add_func(0, 0)) //2  3  0
        fmt.Println(add_func(2, 2)) //3  3  4
    }
    
    // 闭包使用方法,定义add的传参  和函数差不多,再定义fun 可理解匿名函数
    func addNumber(x1, x2 int) func(x3 int, x4 int) (int, int, int) {
        i := 0
        // 这里需要对匿名函数return 理解调用add回调下func,再传参
        return func(x3 int, x4 int) (int, int, int) {
            i++
            //最后return出
            return i, x1 + x2, x3 + x4
        }
    }
    
    package main
    
    import "fmt"
    
    func main() {
        /* add 为一个函数,函数 i 为 0 */
        nextNumber := addNumber()
    
        /* 调用 add 函数,i 变量自增 1 并返回 */
        fmt.Println(nextNumber()) //1
        fmt.Println(nextNumber()) //2
        fmt.Println(nextNumber()) //3
    }
    
    func addNumber() func() int {
        i := 0
        return func() int {
            i++
            return i
        }
    }
    

    关于零值不可用的场景先介绍这些,掌握这些才能在日常开发中减少写bug的频率。

    总结

    总结一下本文叙说的几个知识点:

    • Go语言中所有变量或者值都有默认值,对程序的安全性和正确性起到了很重要的作用。

    • Go语言中的一些标准库利用零值特性来实现,简化操作。

    • 可以利用"零值可用"的特性可以提升代码的结构化、使代码更简单、更紧凑。

    • 零值也不是万能的,有一些场景下零值是不可用的,开发时要注意。

      

      

      

      

  • 相关阅读:
    elementUI .native修饰符
    JS密码强度检测
    HighChart中的tooltip的第一行数字明显比其他的字要小
    HighChart 不同颜色(柱状图)
    .NET(C#、VB)APP开发——Smobiler平台控件介绍:SliderView控件
    .NET(C#、VB)APP开发——Smobiler平台控件介绍:SignatureButton控件
    .NET(WinCE、WM)转Android开发——Xamarin和Smobiler对比
    MobileForm控件的使用方式-用.NET(C#)开发APP的学习日志
    你用.NET开发APP时,在云平台打包APP要填个“包名”的含义
    基于.NET的APP开发和Windows开发,异步回调差别
  • 原文地址:https://www.cnblogs.com/phpper/p/16297982.html
Copyright © 2020-2023  润新知