go 解指针
下面的这个代码没看懂, f2 := (*N).test,解释一下
package main
import "fmt"
type N int
func main() {
case1()
}
func case1() {
var n N = 25
fmt.Printf("main.n:%p,%v\n", &n, n)
n.test()
f1 := N.test
f1(n)
f2 := (*N).test
f2(&n)
}
func (n N) test() {
fmt.Printf("test.n:%p,%v\n", &n, n)
}
你的问题聚焦在代码中的 f2 := (*N).test 这一行,以及它在 Go 中的含义和使用方式。让我逐步拆解这段代码,详细解释它的行为和背后的机制。
完整代码
先看完整代码:
package main
import "fmt"
type N int
func main() {
case1()
}
func case1() {
var n N = 25
fmt.Printf("main.n:%p,%v\n", &n, n) // 输出 n 的地址和值
n.test() // 方法调用
f1 := N.test // 方法表达式,绑定到类型 N
f1(n) // 调用 f1,传入 n
f2 := (*N).test // 方法表达式,绑定到类型 *N
f2(&n) // 调用 f2,传入 &n
}
func (n N) test() {
fmt.Printf("test.n:%p,%v\n", &n, n) // 输出 n 的地址和值
}
运行结果(示例输出,地址会因运行环境变化)
main.n:0xc0000140b8,25
test.n:0xc0000140c0,25
test.n:0xc0000140c8,25
test.n:0xc0000140b8,25
逐步解释
1. type N int 和 (n N) test()
N是一个自定义类型,基于int。(n N) test()定义了一个方法test,它的接收者是N类型的值(值接收者)。- 在 Go 中,方法的接收者可以是值类型(如
N)或指针类型(如*N)。这里是值接收者,意味着调用test时,接收者n是调用者的副本。
2. n.test()
var n N = 25定义了一个变量n,类型是N,值为 25。n.test()是直接调用test方法。- 因为
test的接收者是值类型N,Go 会将n的值复制一份传递给test。 - 输出:
main.n:0xc0000140b8,25:n的地址和值。test.n:0xc0000140c0,25:test中的n是副本,地址不同,但值相同。
3. f1 := N.test
N.test是一种方法表达式(Method Expression)。- 在 Go 中,
T.method(T是类型)会将方法test转换为一个函数,第一个参数是接收者类型T。 - 这里
N.test等价于一个函数签名:func(n N)。 f1(n)调用这个函数,显式传入n作为接收者。- 因为接收者是值类型,
n再次被复制。 - 输出:
test.n:0xc0000140c8,25,地址又不同,因为是新的副本。
4. f2 := (*N).test
(*N).test也是方法表达式,但接收者类型是*N(指向N的指针)。- 尽管
test方法的定义是(n N)(值接收者),Go 允许通过指针类型*N调用值接收者方法。 - 当通过
*N调用时,Go 会自动解引用指针,将值传递给test。 f2的类型等价于func(n *N),需要传入一个*N类型的参数。f2(&n)调用时,传入n的地址(&n),test方法内部会解引用这个地址获取值。- 输出:
test.n:0xc0000140b8,25,地址与main.n相同,因为解引用后直接使用了原始的n。
重点:f2 := (*N).test 的含义
(*N).test表示将test方法绑定到*N类型,而不是N类型。- 在 Go 中,值接收者方法(如
(n N) test())可以通过值类型(如N)或指针类型(如*N)调用:- 如果是值类型调用(
n.test()或f1(n)),会复制值。 - 如果是指针类型调用(
f2(&n)),会传入指针,方法内部解引用访问原始值。
- 如果是值类型调用(
f2的函数签名是func(n *N),需要显式传入一个*N参数(&n),而不是N。
为什么地址相同?
- 在
f2(&n)中,&n是原始变量n的地址(例如0xc0000140b8)。 test方法接收到这个指针后,解引用得到值 25,但&n仍然指向原始变量的地址。- 因此,
fmt.Printf("test.n:%p,%v\n", &n, n)中的&n是原始变量的地址,而不是副本。
与 f1 的区别
f1 := N.test:接收者是值类型N,调用时总是复制n,所以test内的&n是副本地址。f2 := (*N).test:接收者是指针类型*N,调用时传入地址,test解引用后操作的是原始数据。
输出分析
main.n:0xc0000140b8,25 // 原始 n 的地址和值
test.n:0xc0000140c0,25 // n.test(),值复制,新地址
test.n:0xc0000140c8,25 // f1(n),值复制,新地址
test.n:0xc0000140b8,25 // f2(&n),指针解引用,原始地址
- 前两次调用(
n.test()和f1(n))是值传递,test内的n是副本。 - 最后一次调用(
f2(&n))是指针传递,test操作的是原始n的地址。
总结
f2 := (*N).test:- 表示将
test方法绑定到*N类型,生成一个函数func(n *N)。 - 调用时需要传入
*N类型参数(如&n)。 - 方法内部会解引用指针,访问原始值。
- 表示将
- 与
f1 := N.test的区别:f1需要值类型N,总是复制接收者。f2需要指针类型*N,操作原始数据的地址。
- Go 的灵活性:
- 值接收者方法可以通过值或指针调用,指针调用时会自动解引用。
如果你还有疑问或想深入某个部分,随时告诉我!

浙公网安备 33010602011771号