当我将一个新的结构体对象重新分配给一个现有的变量时,地址并没有改变。代码如下所示。
type Request struct {
Field string
}
func main(){
r := Request{Field: "a"}
fmt.Printf("%p\n", &r)
r = Request{Field: "b"}
fmt.Printf("%p\n", &r)
}
输出:
0xc0004040d0
0xc0004040d0
这就像... Feild
被修改,而没有分配新的内存。那么当发生重新分配时,围棋会怎么做呢?
如果我想使用 sync.pool
我可以把obj放到池子里,就像重设一样 r := Request{}
? (我的意思是通过这个操作,struct obj可以重复使用,不会被 gc
.)
规范。复合字元 只说明当你取一个复合字面的地址时,将指向一个未命名的变量,所以需要分配。
当你不取literal的地址只是赋值时,不需要分配,结构体的值可以分配给已经分配了内存的变量。
为了验证,我们可以使用Go的测试框架。创建一个测试文件。
package main
import (
"testing"
)
type Request struct {
Field string
}
var r = Request{Field: "a"}
func BenchmarkStruct(b *testing.B) {
for i := 0; i < b.N; i++ {
r = Request{Field: "b"}
}
}
var p = &Request{Field: "a"}
func BenchmarkStructPtr(b *testing.B) {
for i := 0; i < b.N; i++ {
p = &Request{Field: "b"}
}
}
用它来运行:
go test -bench . -benchmem
输出
BenchmarkStruct-4 1000000000 0.948 ns/op 0 B/op 0 allocs/op
BenchmarkStructPtr-4 32160099 37.3 ns/op 16 B/op 1 allocs/op
正如你所看到的,分配一个你的值 Request
使用复合字元的结构不需要分配。取它的地址并分配需要16个字节的分配(在我的64位架构上),这就是你的 Request
结构,其中包含一个单字段的 string
型,以及 串头 是一个指针(8个字节)和一个长度(8个字节)。
赋值 的值总是会进行复制。所以当你分配任何值(包括结构体的值)时,该值将被复制,而原始值不会被你分配给的变量引用。