Аргументы функции 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
; s
in main
и s
in 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)
Указатели имеют одинаковое значение, когда они указывают на одну и ту же ячейку памяти; указатели имеют разные значения, когда они указывают на разные участки памяти.
s
указатель), - указатели передаются по значению, адресs
не совпадает сs
. Если ваша функция gotest действительноprintln( s )
заинтересовалась, она напечатает значение указателя.В Go аргументы передаются по значению.
package main import "fmt" type SomeStruct struct { e int } // struct passed by value func v(v SomeStruct) { fmt.Printf("v: %p %v\n", &v, v) v.e = 2 fmt.Printf("v: %p %v\n", &v, v) } // pointer to struct passed by value func p(p *SomeStruct) { fmt.Printf("p: %p %v\n", p, *p) p.e = 2 fmt.Printf("p: %p %v\n", p, *p) } func main() { var s SomeStruct s.e = 1 fmt.Printf("s: %p %v\n", &s, s) v(s) fmt.Printf("s: %p %v\n", &s, s) p(&s) fmt.Printf("s: %p %v\n", &s, s) }
Вывод:
s: 0xf800000040 {1} v: 0xf8000000e0 {1} v: 0xf8000000e0 {2} s: 0xf800000040 {1} p: 0xf800000040 {1} p: 0xf800000040 {2} s: 0xf800000040 {2}
источник
type sometype struct { } a := sometype {} b := int(2) println("Ptr to a", &a) println("Ptr to b", &b)
источник
package main import ( "fmt" ) func main() { a := 42 fmt.Println(&a) }
приводит к:
0x1040a124
Согласно Википедии :
источник
package main import "fmt" func zeroval(ival int) { ival = 0 } func zeroptr(iptr *int) { *iptr = 0 } func main() { i := 1 fmt.Println("initial:", i) zeroval(i) fmt.Println("zeroval:", i) //The &i syntax gives the memory address of i, i.e. a pointer to i. zeroptr(&i) fmt.Println("zeroptr:", i) //Pointers can be printed too. fmt.Println("pointer:", &i) }
ВЫВОД:
$ go run pointers.go initial: 1 zeroval: 1 zeroptr: 0 pointer: 0x42131100
источник