Go函数参数按值传递.
首先,让我们go 掉示例中不相关的部分,这样我们就可以很容易地看到您只是按值传递参数.例如,
package main
import "fmt"
func byval(q *int) {
fmt.Printf("3. byval -- q %T: &q=%p q=&i=%p *q=i=%v\n", q, &q, q, *q)
*q = 4143
fmt.Printf("4. byval -- q %T: &q=%p q=&i=%p *q=i=%v\n", q, &q, q, *q)
q = nil
}
func main() {
i := int(42)
fmt.Printf("1. main -- i %T: &i=%p i=%v\n", i, &i, i)
p := &i
fmt.Printf("2. main -- p %T: &p=%p p=&i=%p *p=i=%v\n", p, &p, p, *p)
byval(p)
fmt.Printf("5. main -- p %T: &p=%p p=&i=%p *p=i=%v\n", p, &p, p, *p)
fmt.Printf("6. main -- i %T: &i=%p i=%v\n", i, &i, i)
}
输出:
1. main -- i int: &i=0xf840000040 i=42
2. main -- p *int: &p=0xf8400000f0 p=&i=0xf840000040 *p=i=42
3. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040 *q=i=42
4. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040 *q=i=4143
5. main -- p *int: &p=0xf8400000f0 p=&i=0xf840000040 *p=i=4143
6. main -- i int: &i=0xf840000040 i=4143
在函数main
中,i
是存储器位置(&i
)0xf800000040
处具有初始值(i
)42
的int
变量.
在函数main
中,p
是指向存储器位置(&p
)0xf8000000f0
处的int
变量的指针,其值(p
=&i
)0xf800000040
指向int
值(*p
=i
)42
.
在函数main
中,byval(p)
是将存储器位置(&p
)0xf8000000f0
处的自变量的值(p
=&i
)0xf800000040
分配给存储器位置(&q
)0xf8000000d8
处的函数byval
参数q
的函数调用.换句话说,内存被分配给byval
参数q
,并且main
byval
参数p
的值被分配给它;p
和q
的值最初是相同的,但是变量p
和q
是不同的.
在函数byval
中,使用作为指针p
(*int
)的副本的指针q
(*int
),将整数*q
(i
)设置为新的INT值4143
.在回来之前.指针q
被设置为nil
(零值),这对p
没有影响,因为q
是副本.
在函数main
中,p
是指向存储器位置(&p
)0xf8000000f0
处的int
变量的指针,其值为(p
=&i
)0xf800000040
,该值指向新的int
值(*p
=i
)4143
.
在函数main
中,i
是存储器位置(&i
)0xf800000040
处的int
变量,具有最终值(i
)4143
.
在您的示例中,用作函数gotest
调用参数的函数main
变量s
与函数gotest
参数s
不同.它们具有相同的名称,但是具有不同作用域和内存位置的不同变量.函数参数s
隐藏函数调用参数s
.这就是为什么在我的例子中,我将参数和参数变量分别命名为p
和q
,以强调差异.
在您的示例中,(&s
)0x4930d4
是函数main
中用作函数调用gotest(s, done)
的参数的变量s
的内存位置的地址,而0x4974d8
是函数gotest
参数s
的内存位置的地址.如果在函数gotest
的末尾设置参数s = nil
,则它对main
中的变量s
没有影响;main
中的s
和gotest
中的s
是不同的内存位置.从类型上看,&s
是**Something
,s
是*Something
,*s
是Something
.&s
是指向(存储器位置的地址)s
的指针,其是指向类型Something
的匿名变量(存储器位置的地址)的指针.就值而言,main.&s != gotest.&s
、main.s == gotest.s
、main.*s == gotest.*s
和main.s.number == gotest.s.number
.
你应该接受mkb的明智建议,停止使用println(&s)
.例如,使用fmt
软件包,
fmt.Printf("%v %p %v\n", &s, s, *s)
当指针指向相同的内存位置时,它们具有相同的值;当指针指向不同的内存位置时,它们具有不同的值.