当函数参数是接口时复制的内容

时间:2018-03-07 16:47:31

标签: performance go parameter-passing

假设:在go中,所有函数参数都按值传递。要获得pass-by-reference语义/性能,请让程序员通过指针传递值。 Go仍然会复制这些参数,但它会制作一个指针的副本,这个指针有时比制作实际参数的副本更有效。

问题:通过界面时发生了什么?即,在像这样的程序中

def reverse(sentence):
    answer = ''
    temp = ''
    for char in sentence:
        if char != ' ':
            temp += char
            continue
        rev = ''
        for i in range(len(temp)):
            rev += temp[len(temp)-i-1]
        answer += rev + ' '
        temp = ''
    return answer + temp
reverse("This is a string to try")

当程序员调用package main import "fmt" type Messages struct { hello string } func main() { sayHelloOne(Messages{"hello world"}); sayHelloTwo(&Messages{"hello world"}); sayHelloThree(Messages{"hello world"}); } //go makes a copy of the struct func sayHelloOne(messages Messages) { fmt.Println(messages.hello) } //go makes a *pointer* to the struct func sayHelloTwo(messages *Messages) { fmt.Println(messages.hello) } //go --- ??? func sayHelloThree(messages interface{}) { fmt.Println(messages.(Messages).hello) } 函数时,参数会发生什么? sayHelloThree被复制了吗?或者它是指向messages复制的指针?或者在推出messages之前是否有一些奇怪的推迟?

1 个答案:

答案 0 :(得分:3)

复制接口值。接口值包括底层类型描述符和底层值,它可以是满足接口的任何类型(指针或其他)。被包裹"在接口中对这些语义没有影响。您可以在自己的引用代码中看到这一点:您必须将类型断言为Messages ,而不是*Messages 指针。另一方面,如果您通过了*Messages作为参数,那就是您在函数中获得的内容。

这很容易通过实验证明:

m := Messages{"hello world"}
var mi interface{}
mi = m
m.hello = "wait what?"
fmt.Println(mi.(Messages).hello)
// hello world

工作场所示例:https://play.golang.org/p/lnVzr79eUZF

另外,要小心像&#34这样的概括;制作一个指针的副本,它比制作实际参数的副本更具记忆效率。 - 这并非普遍适用,语义的变化通常比资源使用模式的变化更重要。例如,当值小于操作体系结构上的地址时,指针显然效率较低。指针也可以强制将值强加到堆而不是堆栈,无论它对内存使用的影响如何,都会增加GC压力,因为GC会忽略堆栈上的值。