Go time.Time 应该使用值传递还是指针引用传递

TLDR

大部分场景应该使用值传递。

正文

Go 的文档指出

1
Programs using times should typically store and pass them as values, not pointers. That is, time variables and struct fields should be of type time.Time, not *time.Time. A Time value can be used by multiple goroutines simultaneously.

翻译一下就是

程序使用times典型场景应该把它们当做值传递,而非指针。也就是说time变量及结构体field应该为time.Time,而不是*time.Time。Time值是协程安全的。之所以说typically,是因为有着那么不typically的场景,比如你想在方法内修改原来的time.Time对象这种场景(很少见)。

time.Time是一个较小的对象,把它作为值传递是完全合理的。传递指针而不是值的很重要的一个原因是避免昂贵的拷贝动作。但是传递指针也会给gc带来一些额外的开销,如逃逸分析等。

值得一提的是,你可以通过go build -gcflags="-m"来判断变量在堆中还是在栈中。

go-time-pass

time.Time在我的MBP上只有24个字节。附上几个简单类型的字节数

1
2
3
4
5
6
7
byte size is  1
int32 size is 4
int size is 8
int64 size is 8
float32 size is 4
float64 size is 8
time size is 24

测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package demo_base

import (
"fmt"
"testing"
"time"
"unsafe"
)

func TestSize(t *testing.T) {
{
var x byte = 0
fmt.Println("byte size is ", unsafe.Sizeof(x))
}
{
var x int32 = 0
fmt.Println("int32 size is ", unsafe.Sizeof(x))
}
{
var x int = 0
fmt.Println("int size is ", unsafe.Sizeof(x))
}
{
var x int64 = 0
fmt.Println("int64 size is ", unsafe.Sizeof(x))
}
{
var x float32 = 0
fmt.Println("float32 size is ", unsafe.Sizeof(x))
}
{
var x float64 = 0
fmt.Println("float64 size is ", unsafe.Sizeof(x))
}
{
t := time.Now()
fmt.Println("time size is ", unsafe.Sizeof(t))
}
}