目录
零元素值
nil 比较
new()和&Struct{}
.(type)
if _, ok := v
*pointer
interface
interface拓展
保持好奇心
go
01
零元素值
定义变量时go自动赋予变量初始值
bool | false |
string | "" |
rune | 0 |
iota | 0 |
number | 0 |
other | nil |
nil只能赋值给指针、channel、func、interface、map或slice类型的变量
02
nil 比较
1.不同类型nil值的长度可能不同
2.不同类型nil值可能不能比较
3.map, slice和function,即使在同类型中nil值也不能比较
4.接口与其实现类的nil之间可比较,但为false
03
new()和&Struct{}
1.new(struct)返回指向该结构体的指针,但是所有上述other中提到的类型都会初始化为nil
2.&Struct{}同样返回指向该结构体的指针,但是可以在{}里头去初始化上述other中提到的类型字段
https://stackoverflow.com/questions/4498998/how-to-initialize-members-in-go-struct
04
.(type)
接口判断类型,当any为nil时不会panic
05
if _, ok := v
这是个非常重要的形式,避免后续空指针问题
06
*pointer
对于任意指针,最安全的做法,就是在使用前先进行非空判断,防止后续操作直接使用空指针造成panic
07
interface
先看一个比较有趣的问题:
上面打印出来的结果
一般来说,等号具有传递性,第四句打印为什么会为false?
go中的interface可以认为是一个二元组(T, V),如var i interface{} = 3,就会被认为是(T=int, V=3)
https://golang.org/doc/faq#nil_error
通过上述的资料可知,go在编译的时候,因为convert函数的返回值类型为error,第四句打印的nil类型被认作是 (error)nil,因此在interface的相等判断中,会被认为是不相等的。上述三句判断的类型如下:
(*Err)err == (*Err)nil
(*Err)errR == (error)nil
(*Err)errR == (*Err)err
因此,如果将第四句nil修改为:
fmt.Println(errR == (*Err)(nil))
则结果就为true。
08
interface拓展
更详细介绍interface可以阅读这个文档:
https://research.swtch.com/interfaces
interface{}符合鸭子类型,但底层仍然是静态类型interface,不保证任何方法,运行时会找到对应的方法。interface包含两个机器字,一个指向类型itable,一个指向值,如图
itable会记录开头会记录一些类型的元数据,随后记录着指向函数方法的指针列表。指向变量的指针指向数据的拷贝。
编译器为每个具体类型生成类型描述结构体。类型描述结构包含该类型实现的方法的列表。接口运行时通过在具体类型的方法表中查找接口类型的方法表中列出的每个方法。itable生成后就会被缓存起来。
interface的静态类型会决定哪些方法可以被调用,即使变量包含了更多的方法集。
https://blog.golang.org/laws-of-reflection
举个例子:
如注释所示,虽然r, w, empty的接口的类型都是*os.File,但底层itable表所拥有的函数子集不同导致可用函数也有所不同。
以上就是我所了解到的关于空指针的一小部分内容,也可能有理解错误的地方,欢迎各位大佬们指正与指导!
v1.1