背景

Google工程师Valentin Deleplace出了1道关于变量初始化的题目,本来以为很简单,没想到回答正确率不到30%,拿出来和大家分享下。

题目

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// quiz.go
package main

import "fmt"

func main() {
	var a *int
	*a = 5.0
	fmt.Println(*a)
}
  • A: 5

  • B: 5.0

  • C: panic

  • D: 编译错误

解析

这道题主要考察2个知识点:

  • 变量零值。题目中a是一个指针类型的变量,var a *int这行代码没有对变量a初始化赋值,所以变量a的值是零值,指针的零值是nil,所以a的值是nil

  • 变量初始化赋值。如果对int类型的变量赋值为浮点数5.0是合法的,因为5.0是untyped float constant,是可以在不损失精度的情况下转换为5的。如果是赋值为5.1那就非法了,因为要损失小数点后面的精度,编译报错如下:

    1
    
    ./quiz1.go:8:7: cannot use 5.1 (untyped float constant) as int value in assignment (truncated)
    

所以本题答案是C,编译的时候不会报错,但是运行的时候因为a 的值是nil,对nil*操作就会引发panic,具体panic内容为:panic: runtime error: invalid memory address or nil pointer dereference

思考题

题目1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// quiz1.go
package main

import "fmt"

func main() {
	var a *int = new(int)
	*a = 5.0
	fmt.Println(*a)
}

题目2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// quiz2.go
package main

import "fmt"

func main() {
	var a *int = new(int)
	var b float32 = 5.0
	*a = b
	fmt.Println(*a)
}

题目3:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// quiz3.go
package main

import "fmt"

func main() {
	var a *int = new(int)
	*a = 5.1
	fmt.Println(*a)
}

想知道答案的可以给公众号发送消息init获取答案。

总结

Go语言里不同类型的变量的零值不一样,给大家总结了各个类型的变量的零值:

  • 数值:所有数值类型的零值都是0

    • 整数,零值是0。byte, rune, uintptr也是整数类型,所以零值也是0。
    • 浮点数,零值是0
    • 复数,零值是0+0i
    • 整数类型的变量是可以用untyped float constant进行赋值的,只要不损失精度即可。
  • bool,零值是false

  • 字符串,零值是空串""

  • 指针:var a *int,零值是nil

    1
    2
    
    num := 100
    var a * int = &num
    
  • 切片:var a []int,零值是nil

    1
    2
    
    var a []int = []int{1,2}
    list := [6]int{1,2} //size为6的数组,前面2个元素是1和2,后面的是默认值0
    
  • map:var a map[string] int,零值是nil

    1
    
    dict := map[string] int{"a":1, "b":2}
    
  • 函数:var a func(string) int,零值是nil

    1
    2
    3
    4
    5
    
    function := func(str string) string {
      return str
    }
    result := function("hello fans")
    fmt.Println("result=", result)
    
  • channel:var a chan int,通道channel,零值是nil

    1
    2
    3
    
    var a chan int = make(chan int)
    var b = make(chan string)
    c := make(chan bool)
    
  • 接口:var a interface_type,接口interface,零值是nil

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    type Animal interface {
      speak()
    }
    
    type Cat struct {
      name string
      age int
    }
    
    func(cat Cat) speak() {
      fmt.Println("miao...")
    }
    
    // 定义一个接口变量a
    var a Animal = Cat{"gaffe", 1}
    a.speak() // miao...
    
  • 结构体: var instance StructName,结构体里每个field的零值是对应field的类型的零值

    1
    2
    3
    4
    5
    6
    
    type Circle struct {
      radius float64
    }
    
    var c1 Circle
    c1.radius = 10.00
    

开源地址

文章和示例代码开源在GitHub: Go语言初级、中级和高级教程

公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。

个人网站:Jincheng’s Blog

知乎:无忌

References