去隐式转换到接口做内存分配?

时间:2016-09-14 14:07:01

标签: go

当定义具有类型interface{}的可变参数的函数(例如Printf)时,参数显然被隐式转换为接口实例。

此转换是否意味着内存分配?转换速度快吗?当关注代码效率时,我应该避免使用可变参数函数吗?

3 个答案:

答案 0 :(得分:4)

我发现关于Go中接口内存分配的最佳解释仍然是来自Rus Cox的核心Go程序员之一。值得一读。

<强> http://research.swtch.com/interfaces

我选择了一些最有趣的部分:

  

存储在接口中的值可能是任意大的,但只有一个   word专门用于保存接口结构中的值,所以   赋值在堆上分配一块内存并记录   单字槽中的指针。

     

...

     

调用fmt.Printf(),Go编译器生成调用的代码   适当的函数指针来自itable,传递接口   value的数据字作为函数的第一个(仅在此示例中)   参数。

     

Go的动态类型转换意味着它不合理   编译器或链接器预先计算所有可能的itables:也有   许多(接口类型,具体类型)对,大多数将不需要。   相反,编译器为每个生成类型描述结构   具体类型如Binary或int或func(map [int] string)。除其他外   元数据,类型描述结构包含一个列表   由该类型实现的方法。

     

...

     

接口运行时通过查找每个方法来计算itable   在具体类型的接口类型的方法表中列出   方法表。生成器运行后缓存itable,因此   这种对应只需要计算一次。

     

...

     

如果涉及的接口类型为空 - 它没有方法 - 那么   除了将指针保持在原始状态之外,itable没有用处   类型。在这种情况下,可以删除itable并且值可以指向   在类型直接。

因为Go有动态方法查找的静态类型提示,它可以将查询从调用站点移回到值存储在接口中的点。

答案 1 :(得分:2)

转换为interface{}是一个独立于可变参数的概念,它包含在切片中,可以是任何类型。但是,只要它们不会逃逸到堆中(在GC工具链中),这些都可能在分配意义上是免费的。

您从fmt函数中看到的超额分配(例如Printf)将来自反思,而不是使用interface{}或可变参数。

如果您关注效率,那么避免间接将始终更有效,因此使用正确的值类型将产生更高效的代码。但差异可能很小,因此在对自己进行微小优化之前先对代码进行基准测试。

答案 2 :(得分:0)

Go传递参数copy_by_value,因此它无论如何都会进行内存分配。如果可能的话,你总是应该更好地避免使用接口{}。在描述的情况下,您的函数将需要反映使用它们的参数。反思是非常昂贵的操作,这就是fmt.Printf()如此缓慢的原因。