Argumenty funkcji Go są przekazywane przez wartość.
Po pierwsze, odrzućmy nieistotne części twojego przykładu, abyśmy mogli łatwo zobaczyć, że przekazujesz argument według wartości. Na przykład,
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)
}
Wynik:
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
Funkcja main, ijest intzmienna w miejscu pamięci ( &i) 0xf800000040o początkowej wartości ( i) 42.
W zależności main, pto wskaźnik do intzmiennej w miejscu pamięci ( &p) 0xf8000000f0o wartości ( p= &i) 0xf800000040, który wskazuje na intwartość ( *p= i) 42.
W zależności main, byval(p)to wywołanie funkcji, która przypisuje wartości ( p= &i) 0xf800000040argumentu w komórce pamięci ( &p) 0xf8000000f0do funkcji byvalparametru qw miejscu pamięci ( &q) 0xf8000000d8. Innymi słowy, pamięć jest przydzielana dla byvalparametru qi przypisywana jest do niego wartość main byvalargumentu p; wartości pi qsą początkowo takie same, ale zmienne pi qsą różne.
W funkcji byval, używając pointer q( *int), który jest kopią pointer p( *int), integer *q( i) jest ustawiana na nową wartość int 4143. Na koniec przed powrotem. wskaźnik qjest ustawiony na nil(wartość zerowa), co nie ma wpływu na to, pże qjest kopią.
W zależności main, pto wskaźnik do intzmiennej w miejscu pamięci ( &p) 0xf8000000f0o wartości ( p= &i), 0xf800000040co wskazuje na nową intwartość ( *p= i) 4143.
Funkcja main, ijest intzmienna w miejscu pamięci ( &i) 0xf800000040o wartości końcowej ( i) 4143.
W naszym przykładzie mainzmienna funkcji sużywana jako argument gotestwywołania funkcji nie jest tym samym, co gotestparametr funkcji s. Mają tę samą nazwę, ale są różnymi zmiennymi z różnymi zakresami i lokalizacjami pamięci. Parametr funkcji sukrywa argument wywołania funkcji s. Dlatego w moim przykładzie nazwałem zmienne argumentu i parametru poraz qodpowiednio, aby podkreślić różnicę.
W naszym przykładzie ( &s) 0x4930d4jest adresem lokalizacji pamięci dla zmiennej sw funkcji, mainktóra jest używana jako argument wywołania funkcji gotest(s, done), i 0x4974d8jest adresem lokalizacji pamięci dla gotestparametru funkcji s. Jeśli ustawisz parametr s = nilna końcu funkcji gotest, nie będzie to miało wpływu na zmienną sin main; sin maini sin gotestto różne lokalizacje pamięci. Pod względem typów &sjest **Something, sjest *Somethingi *sjest Something. &sjest wskaźnikiem na (adres lokalizacji pamięci) s, który jest wskaźnikiem do (adres lokalizacji pamięci) anonimowej zmiennej typuSomething. Pod względem wartości, main.&s != gotest.&s, main.s == gotest.s, main.*s == gotest.*s, i main.s.number == gotest.s.number.
Powinieneś skorzystać z mądrej rady mkb i przestać używać println(&s). Skorzystaj z fmtpakietu, na przykład
fmt.Printf("%v %p %v\n", &s, s, *s)
Wskaźniki mają tę samą wartość, gdy wskazują to samo miejsce w pamięci; wskaźniki mają różne wartości, gdy wskazują różne lokalizacje pamięci.