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
, i
jest int
zmienna w miejscu pamięci ( &i
) 0xf800000040
o początkowej wartości ( i
) 42
.
W zależności main
, p
to wskaźnik do int
zmiennej w miejscu pamięci ( &p
) 0xf8000000f0
o wartości ( p
= &i
) 0xf800000040
, który wskazuje na int
wartość ( *p
= i
) 42
.
W zależności main
, byval(p)
to wywołanie funkcji, która przypisuje wartości ( p
= &i
) 0xf800000040
argumentu w komórce pamięci ( &p
) 0xf8000000f0
do funkcji byval
parametru q
w miejscu pamięci ( &q
) 0xf8000000d8
. Innymi słowy, pamięć jest przydzielana dla byval
parametru q
i przypisywana jest do niego wartość main
byval
argumentu p
; wartości p
i q
są początkowo takie same, ale zmienne p
i q
są 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 q
jest ustawiony na nil
(wartość zerowa), co nie ma wpływu na to, p
że q
jest kopią.
W zależności main
, p
to wskaźnik do int
zmiennej w miejscu pamięci ( &p
) 0xf8000000f0
o wartości ( p
= &i
), 0xf800000040
co wskazuje na nową int
wartość ( *p
= i
) 4143
.
Funkcja main
, i
jest int
zmienna w miejscu pamięci ( &i
) 0xf800000040
o wartości końcowej ( i
) 4143
.
W naszym przykładzie main
zmienna funkcji s
używana jako argument gotest
wywołania funkcji nie jest tym samym, co gotest
parametr funkcji s
. Mają tę samą nazwę, ale są różnymi zmiennymi z różnymi zakresami i lokalizacjami pamięci. Parametr funkcji s
ukrywa argument wywołania funkcji s
. Dlatego w moim przykładzie nazwałem zmienne argumentu i parametru p
oraz q
odpowiednio, aby podkreślić różnicę.
W naszym przykładzie ( &s
) 0x4930d4
jest adresem lokalizacji pamięci dla zmiennej s
w funkcji, main
która jest używana jako argument wywołania funkcji gotest(s, done)
, i 0x4974d8
jest adresem lokalizacji pamięci dla gotest
parametru funkcji s
. Jeśli ustawisz parametr s = nil
na końcu funkcji gotest
, nie będzie to miało wpływu na zmienną s
in main
; s
in main
i s
in gotest
to różne lokalizacje pamięci. Pod względem typów &s
jest **Something
, s
jest *Something
i *s
jest Something
. &s
jest 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 fmt
pakietu, 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.