Golang指针相关的问题探讨
Golang指针相关的问题探讨 我是新手,有几个问题。关于这段代码片段,我有一些疑问。
package main
type Dummy struct {
Name *string `json:"name"`
Image *string `json:"image"`
}
func dummyFunc() Dummy {
row := database.DbConn.QueryRow("SELECT name, image FROM mytable WHERE id=5")
var dummy Dummy
row.Scan(&dummy.Name, &dummy.Image)
return dummy
}
我运行了这段代码,令我惊讶的是,dummy.Name 和 dummy.Image 的值竟然能够被设置,但我不明白这是如何实现的。我在调试器中再次确认了 Name 和 Image 是 nil。希望有人能为我解释一下。另一个问题是,在一个指针类型前面加上 & 是什么意思?那就像是地址的地址吗?这怎么可能呢?我有点困惑。非常感谢。
更多关于Golang指针相关的问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html
Name *string 意味着 Name 是一个指针类型,指向一个 string 的位置。
&dummy.Name 表示指向变量 dummy 的指针,而 dummy 是 Dummy 的一个 “接口类型”。
接口类型 包含一个指针类型和一个值类型。
你的理解是正确的,如果你对 var *string 类型的变量使用 &var,那将得到一个指向指针的指针。但你现在操作的是指向一个包含指针的值类型的指针。
在某些情况下,Go 和一些库会进行一些魔法操作,自动隐式地解引用指针,这有时仍然会让我感到困惑。但幸运的是,当我尝试使用别人混合了指针和值类型的代码时,JetBrains GoLand 通常会建议正确的修复方法使其正常工作。
这是一个很好的问题,涉及到Go中指针和database/sql包的工作机制。
首先,你的代码能够工作是因为database/sql包在Scan()方法内部处理了指针的指针。当你调用row.Scan(&dummy.Name, &dummy.Image)时:
dummy.Name和dummy.Image已经是*string类型(指向string的指针)- 加上
&后,你传递的是**string类型(指向指针的指针) Scan()方法内部会分配新的字符串内存,并将指针指向这个内存
这里是一个简化的示例来说明这个过程:
package main
import (
"fmt"
)
type Dummy struct {
Name *string
Image *string
}
// 模拟Scan函数的行为
func mockScan(namePtr **string, imagePtr **string) {
// 分配新的字符串
nameValue := "John Doe"
imageValue := "profile.jpg"
// 将指针指向新分配的内存
*namePtr = &nameValue
*imagePtr = &imageValue
}
func main() {
var dummy Dummy
// 传递指针的地址,这样mockScan可以修改指针本身
mockScan(&dummy.Name, &dummy.Image)
fmt.Printf("Name: %s\n", *dummy.Name) // 输出: Name: John Doe
fmt.Printf("Image: %s\n", *dummy.Image) // 输出: Image: profile.jpg
}
关于你的第二个问题:在指针类型前面加上 & 确实是"地址的地址"。这在Go中是合法的,因为:
- 指针本身也是一个变量,存储在内存中
- 指针变量也有自己的内存地址
- 你可以获取任何变量的地址,包括指针变量
示例:
package main
import "fmt"
func main() {
var x int = 10
var ptr *int = &x // ptr是指向int的指针
var pptr **int = &ptr // pptr是指向指针的指针
fmt.Printf("x的值: %d\n", x) // 10
fmt.Printf("ptr指向的值: %d\n", *ptr) // 10
fmt.Printf("pptr指向的指针指向的值: %d\n", **pptr) // 10
// 修改原始值
**pptr = 20
fmt.Printf("修改后x的值: %d\n", x) // 20
}
在你的数据库代码中,Scan()方法需要接收**string(指针的指针)的原因是:
- 如果只传递
*string,Scan()只能修改指针指向的值 - 但你的结构体字段初始是
nil,需要Scan()能够分配内存并设置指针指向新内存 - 所以需要传递指针的地址,让
Scan()能够修改指针本身
这就是为什么即使dummy.Name和dummy.Image初始为nil,代码仍然能正常工作的原因。Scan()方法内部处理了内存分配和指针设置。

