Аргументи функції 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, це не вплине на змінну sin 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)
Покажчики мають однакове значення, коли вони вказують на одне і те ж місце пам'яті; покажчики мають різні значення, коли вони вказують на різні місця пам'яті.