Аргументы функции 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при использовании pointer q( *int), который является копией pointer p( *int), integer *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в main; sin mainи sin 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)
Указатели имеют одинаковое значение, когда они указывают на одну и ту же ячейку памяти; указатели имеют разные значения, когда они указывают на разные участки памяти.