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
是int
位于内存位置(&i
)的0xf800000040
具有初始值(i
)的变量42
。
在函数中main
,p
是指向int
内存位置(&p
)处的变量的指针,该变量0xf8000000f0
的值(p
=&i
)0xf800000040
指向int
值(*p
= i
)42
。
在功能main
,byval(p)
是一个函数调用,其将值(p
=&i
)0xf800000040
在存储器位置(自变量的&p
)0xf8000000f0
给函数byval
参数q
在存储器位置(&q
)0xf8000000d8
。换句话说,存储器被分配用于byval
参数q
和的值main
byval
的参数p
被分配给它; 的值p
和q
最初是相同的,但变量p
和q
是不同的。
在功能byval
,使用指针q
(*int
),它是指针的一个拷贝p
(*int
),整数*q
(i
)被设置为一个新的int值4143
。最后返回之前。指针q
设置为nil
(零值),p
由于q
是副本,因此不起作用。
在函数中main
,p
是指向int
内存位置(&p
)的变量的指针,该变量0xf8000000f0
的值(p
=&i
)0xf800000040
指向新int
值(*p
= i
)4143
。
在函数中main
,i
是int
位于内存位置(&i
)的变量,0xf800000040
具有最终值(i
)4143
。
在您的示例中,用作函数调用参数的函数main
变量与function 参数不同。它们具有相同的名称,但是是具有不同作用域和存储位置的不同变量。函数参数隐藏函数调用参数。这就是为什么在我的例子,我命名的参数和参数变量,并分别以强调差异。s``gotest``gotest``s``s``s``p``q
在您的示例中,(&s
)0x4930d4
是s
函数main
中变量的存储位置的地址,用作函数调用的参数gotest(s, done)
,并且0x4974d8
是函数gotest
参数的存储位置的地址s
。如果s = nil
在函数末尾设置参数gotest
,则它对s
in中的变量没有影响main
;s
in main
和s
ingotest
是不同的内存位置。就类型而言,&s
is **Something
,s
is *Something
和*s
isSomething
。&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)
当指针指向相同的存储位置时,它们具有相同的值。指针指向不同的内存位置时,它们具有不同的值。