我对在 Go 中通过引用和值传递有点困惑。
我已经看到对类型前面的 * 进行了解释。
- 在类型名称前面,意味着声明的变量将存储该类型的另一个变量的地址(不是该类型的值)。
这对我来说没有意义。
在 Java 中,如果我将数据库实例传递给函数,我会这样做
databaseFunction(DatabaseType db) {
// do something
}
Run Code Online (Sandbox Code Playgroud)
但是在 go 示例中,我已经通过了它。
func PutTasks(db *sql.DB) echo.HandlerFunc {
}
Run Code Online (Sandbox Code Playgroud)
为什么我们需要在类型前面加上星号?
根据这个备忘单,我找到了。
func PrintPerson(p *Person) 只接收指针地址(引用)
我不明白为什么我只想发送一个指针地址作为参数。
Adr*_*ian 28
首先,从技术上讲,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!
}
Run Code Online (Sandbox Code Playgroud)
至于你的问题“为什么我们需要在类型前面加上星号?”:星号表示该值是指向 的类型sql.DB,而不是类型的值sql.DB。这些不能互换!
为什么要发送指针地址?这样你就可以在函数的调用者和函数体之间共享值,函数内部所做的更改反映在调用者中(例如,指针是“setter”方法可以在对象上工作的唯一方式) . Java 总是通过引用传递对象,而 Go 总是通过值传递(即它在函数中创建值的副本);如果您将某些内容传递给函数,并且该函数修改了该值,则调用者将看不到这些更改。如果您希望更改在函数外传播,则必须传递一个指针。
另请参阅:指针的Go 导览部分、指针的Go 规范部分、地址运算符的Go 规范部分
引用语义的目的是允许函数在其自身范围之外操作数据。相比:
func BrokenSwap(a int, b int) {
a, b = b, a
}
func RealSwap(a *int, b *int) {
*a, *b = *b, *a
}
Run Code Online (Sandbox Code Playgroud)
当您调用 时BrokenSwap(x, y),没有任何效果,因为该函数接收并操作数据的私有副本。相比之下,当您调用 时RealSwap(&x, &y),您实际上交换了调用者的 x和的值y。在调用站点明确获取变量的地址会通知读者这些变量可能会发生变异。