我对Go中的引用和值传递感到有点困惑。
我已经在类型前面看到了*的解释。
- 在类型名称前面,意味着声明的变量将存储该类型的另一个变量的地址(不是该值的值) 类型)。
这对我来说没有意义。
在Java中如果我将数据库实例传递给函数我会做
databaseFunction(DatabaseType db) {
// do something
}
然而,在go示例中,我已经这样通过了。
func PutTasks(db *sql.DB) echo.HandlerFunc {
}
为什么我们需要在类型前面加上星号?
根据这张备忘单,我找到了。
func PrintPerson(p * Person)仅接收指针地址 (参考)
我不明白为什么我只想将指针地址作为参数发送。
答案 0 :(得分:4)
首先,Go在技术上只有按值传递。将指针传递给对象时,您需要按值传递指针,而不是通过引用传递对象。差异很微妙,但偶尔相关。例如,您可以覆盖对调用者没有影响的指针值,而不是取消引用它并覆盖它指向的内存。
// *int means you *must* pass a *int (pointer to int), NOT just an int!
func someFunc(x *int) {
*x = 2 // Whatever variable caller passed in will now be 2
y := 7
x = &y // has no impact on the caller because we overwrote the pointer value!
}
关于你的问题"为什么我们需要在类型前面加上星号?":星号表示该值是指向sql.DB
的类型指针,而不是类型sql.DB
的值。这些不可互换!
为什么要发送指针地址?这样你就可以在一个函数的调用者和函数体之间共享一个值,函数内部的变化反映在调用者中(例如,一个指针是唯一的方式一个&#34 ; setter"方法可以处理对象)。虽然Java始终通过引用传递对象,但Go始终按值传递(即它在函数中创建值的副本);如果您将某些内容传递给某个函数,并且该函数修改了该值,则调用者将无法看到这些更改。如果您希望更改在函数外部传播,则必须传递指针。
另请参阅:Go tour section on Pointers,Go spec section on pointers,Go spec section on the address operators
答案 1 :(得分:2)
引用语义的目的是允许函数在其自己的范围之外操作数据。比较:
func BrokenSwap(a int, b int) {
a, b = b, a
}
func RealSwap(a *int, b *int) {
*a, *b = *b, *a
}
当您调用BrokenSwap(x, y)
时,没有任何效果,因为该函数接收并操作数据的私有副本。相反,当您致电RealSwap(&x, &y)
时,您实际上会交换来电者 x
和y
的值。在呼叫站点明确地获取变量的地址会通知读者这些变量可能会发生变异。