Go
Wskaźniki
Szukaj…
Składnia
- wskaźnik: = i zmienna // pobierz wskaźnik ze zmiennej
- zmienna: = * wskaźnik // pobierz zmienną ze wskaźnika
- * wskaźnik = wartość // ustaw wartość od zmiennej poprzez wskaźnik
- pointer: = new (Struct) // pobierz wskaźnik nowej struktury
Podstawowe wskaźniki
Go obsługuje wskaźniki , pozwalając na przekazywanie referencji do wartości i rekordów w twoim programie.
package main
import "fmt"
// We'll show how pointers work in contrast to values with
// 2 functions: `zeroval` and `zeroptr`. `zeroval` has an
// `int` parameter, so arguments will be passed to it by
// value. `zeroval` will get a copy of `ival` distinct
// from the one in the calling function.
func zeroval(ival int) {
ival = 0
}
// `zeroptr` in contrast has an `*int` parameter, meaning
// that it takes an `int` pointer. The `*iptr` code in the
// function body then _dereferences_ the pointer from its
// memory address to the current value at that address.
// Assigning a value to a dereferenced pointer changes the
// value at the referenced address.
func zeroptr(iptr *int) {
*iptr = 0
}
Po zdefiniowaniu tych funkcji możesz wykonać następujące czynności:
func main() {
i := 1
fmt.Println("initial:", i) // initial: 1
zeroval(i)
fmt.Println("zeroval:", i) // zeroval: 1
// `i` is still equal to 1 because `zeroval` edited
// a "copy" of `i`, not the original.
// The `&i` syntax gives the memory address of `i`,
// i.e. a pointer to `i`. When calling `zeroptr`,
// it will edit the "original" `i`.
zeroptr(&i)
fmt.Println("zeroptr:", i) // zeroptr: 0
// Pointers can be printed too.
fmt.Println("pointer:", &i) // pointer: 0x10434114
}
Wskaźnik v. Metody wartości
Metody wskaźnika
Metody wskaźnikowe można wywoływać, nawet jeśli zmienna sama w sobie nie jest wskaźnikiem.
Według specyfikacji Go ,
. . . odniesienie do metody nieinterfejsowej z odbiornikiem wskaźnikowym wykorzystującej wartość adresowalną automatycznie przyjmuje adres tej wartości:
t.Mp
jest równoważne(&t).Mp
.
Możesz to zobaczyć w tym przykładzie:
package main
import "fmt"
type Foo struct {
Bar int
}
func (f *Foo) Increment() {
f.Bar += 1
}
func main() {
var f Foo
// Calling `f.Increment` is automatically changed to `(&f).Increment` by the compiler.
f = Foo{}
fmt.Printf("f.Bar is %d\n", f.Bar)
f.Increment()
fmt.Printf("f.Bar is %d\n", f.Bar)
// As you can see, calling `(&f).Increment` directly does the same thing.
f = Foo{}
fmt.Printf("f.Bar is %d\n", f.Bar)
(&f).Increment()
fmt.Printf("f.Bar is %d\n", f.Bar)
}
Metody wyceny
Podobnie jak w przypadku metod wskaźnikowych, metody wartości można wywoływać, nawet jeśli sama zmienna nie jest wartością.
Według specyfikacji Go ,
. . . odniesienie do metody nieinterfejsowej z odbiornikiem wartości za pomocą wskaźnika automatycznie
pt.Mv
ten wskaźnik:pt.Mv
jest równoważne(*pt).Mv
.
Możesz to zobaczyć w tym przykładzie:
package main
import "fmt"
type Foo struct {
Bar int
}
func (f Foo) Increment() {
f.Bar += 1
}
func main() {
var p *Foo
// Calling `p.Increment` is automatically changed to `(*p).Increment` by the compiler.
// (Note that `*p` is going to remain at 0 because a copy of `*p`, and not the original `*p` are being edited)
p = &Foo{}
fmt.Printf("(*p).Bar is %d\n", (*p).Bar)
p.Increment()
fmt.Printf("(*p).Bar is %d\n", (*p).Bar)
// As you can see, calling `(*p).Increment` directly does the same thing.
p = &Foo{}
fmt.Printf("(*p).Bar is %d\n", (*p).Bar)
(*p).Increment()
fmt.Printf("(*p).Bar is %d\n", (*p).Bar)
}
Aby dowiedzieć się więcej o metodach wskaźnikowych i wartościowych, odwiedź sekcję Go Spec w Method Values lub zobacz Efektywną wersję Go o Pointers v. Values .
Uwaga 1: Nawiasy ( ()
) wokół *p
i &f
przed selektorami, takimi jak .Bar
służą do grupowania i muszą zostać zachowane.
Uwaga 2: Chociaż wskaźniki mogą być konwertowane na wartości (i odwrotnie), gdy są odbiornikami metody, nie są one automatycznie konwertowane na siebie, gdy są argumentami wewnątrz funkcji.
Wskaźniki dereferencyjne
Wskaźniki mogą być dereferencjonowane dodając gwiazdkę * przed wskaźnikiem.
package main
import (
"fmt"
)
type Person struct {
Name string
}
func main() {
c := new(Person) // returns pointer
c.Name = "Catherine"
fmt.Println(c.Name) // prints: Catherine
d := c
d.Name = "Daniel"
fmt.Println(c.Name) // prints: Daniel
// Adding an Asterix before a pointer dereferences the pointer
i := *d
i.Name = "Ines"
fmt.Println(c.Name) // prints: Daniel
fmt.Println(d.Name) // prints: Daniel
fmt.Println(i.Name) // prints: Ines
}
Plasterki są wskaźnikami do segmentów macierzy
Plasterki są wskaźnikami do tablic, o długości segmentu i jego pojemności. Zachowują się jak wskaźniki, a przypisanie ich wartości do innego wycinka spowoduje przypisanie adresu pamięci. Aby skopiować wartość wycinka do innej, użyj wbudowanej funkcji kopiowania : func copy(dst, src []Type) int
(zwraca liczbę skopiowanych elementów).
package main
import (
"fmt"
)
func main() {
x := []byte{'a', 'b', 'c'}
fmt.Printf("%s", x) // prints: abc
y := x
y[0], y[1], y[2] = 'x', 'y', 'z'
fmt.Printf("%s", x) // prints: xyz
z := make([]byte, len(x))
// To copy the value to another slice, but
// but not the memory address use copy:
_ = copy(z, x) // returns count of items copied
fmt.Printf("%s", z) // prints: xyz
z[0], z[1], z[2] = 'a', 'b', 'c'
fmt.Printf("%s", x) // prints: xyz
fmt.Printf("%s", z) // prints: abc
}
Proste wskaźniki
func swap(x, y *int) {
*x, *y = *y, *x
}
func main() {
x := int(1)
y := int(2)
// variable addresses
swap(&x, &y)
fmt.Println(x, y)
}