我们看个空结构体例子:
package main
import "fmt"
type User struct{
}
func test(u User){
fmt.Printf("test: %p\n",&u)
}
func main() {
user:=User{}
test(user)
fmt.Printf("main-user: %p\n",&user)
}
结果:
test: 0x5a6d68
main-user: 0x5a6d68
我们再看一下不是空结构体是什么结果:
package main
import "fmt"
type User struct{
age int
}
func test(u User){
fmt.Printf("test: %p\n",&u)
}
func main() {
user:=User{age:90}
test(user)
fmt.Printf("main-user: %p\n",&user)
}
结果:
test: 0xc00000a0c8
main-user: 0xc00000a0c0
我们发现空结构体地址是一样的,非空结构体地址不一样,Go语言不是只有值传递嘛,为什么第一种不是这样的情况呢?
感兴趣的伙伴可以执行go tool compile -N -l -S main.go,可以得到汇编部分
通过runtime.newobject(SB)分配内存:
func newobject(typ *_type) unsafe.Pointer {
return mallocgc(typ.size, typ, true)
}
newobject()中主要是调用了mallocgc()方法,在这里我找到了答案。因为mallocgc()代码比较长
如果 size 为 0 的时候,统一返回的都是全局变量 zerobase 的地址。【PS:正常struct是占用一小块内存的,并且结构体的大小是要经过边界,长度的对齐的,但是“空结构体”是不占内存的,size为0】。总结原因:
因为空结构体是不占用内存的,所以
size为0,在内存分配时,size为0会统一返回zerobase的地址,所以空结构体在进行参数传递时,发生值拷贝后地址都是一样的,才造成了这个质疑Go不是值传递的假象。
也就是说如果我定义了两个空结构体,那么他们的地址应该是一样的,我们来验证一下:
package main
import (
"fmt"
)
type User struct {
}
type Dog struct {
}
func main() {
user := User{}
dog := Dog{}
fmt.Printf("main-user: %p\n", &user)
fmt.Printf("main-dog: %p\n", &dog)
}
结果:
main-user: 0x5a6d68
main-dog: 0x5a6d68
结果证明果然是一样的。