Аргументы функции 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
переменная 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
в main
и s
в gotest
- это отдельные области памяти.С точки зрения типов, &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)
Указатели имеют одинаковое значение, когда они указывают на одну и ту же область памяти;указатели имеют разные значения, когда они указывают на разные области памяти.