返回接口{}而不是int64时的额外分配

fel*_*lix 0 memory types allocation object go

我有一个生成随机的函数,int64并返回interface{}如下:

func Val1(rnd rand.Source) interface{} {
 return rnd.Int63() 
} 
Run Code Online (Sandbox Code Playgroud)

现在考虑这个函数,它做同样的事情,但返回一个 int64

func Val2(rnd rand.Source) int64 {
 return rnd.Int63()
}
Run Code Online (Sandbox Code Playgroud)

我使用this(go test -bench=. -benchmem)对这两个函数进行了基准测试:

func BenchmarkVal1(b *testing.B) {
    var rnd = rand.NewSource(time.Now().UnixNano())
    for n := 0; n < b.N; n++ {
        Val1(rnd)
    }
}

func BenchmarkVal2(b *testing.B) {
    var rnd = rand.NewSource(time.Now().UnixNano())
    for n := 0; n < b.N; n++ {
        Val2(rnd)
    }
}
Run Code Online (Sandbox Code Playgroud)

得到了以下结果:

BenchmarkVal1-4    50000000         32.4 ns/op         8 B/op          1 allocs/op
BenchmarkVal2-4    200000000        7.47 ns/op         0 B/op          0 allocs/op
Run Code Online (Sandbox Code Playgroud)

额外分配Val1()来自哪里?返回时可以避免interface{}吗?

icz*_*cza 5

接口值是引擎盖下的一个包装器,一对存储在接口值中的具体值及其类型描述符.

阅读本文以获取更多信息:反射定律#界面的表示

因此,如果要返回interface{}type的interface{}值,将隐式创建一个值(如果返回的值不是该类型的值),它将保存整数,其类型描述符表示int64类型.你无法避免这种情况.

interface{}是一种特殊的接口类型(有0种方法).正如您在基准输出上看到的,它的值只有8个字节.其他接口类型具有更大的大小(双倍),因为它们还必须标识接口类型的静态方法集(除了动态类型和值).

另外请务必查看这个内容丰富的答案:Go:interface {}的含义是什么?

如果您想了解有关实现/内部的更多信息,我建议这篇文章:接口如何在Golang中工作