MySQL Java JavaScript PHP Python HTML-CSS C-sharp C++ Go

Pointers

Ce sunt Pointers?

Pointers sunt obiecte ale căror valoare reprezintă adresa altor obiecte (de exemplu, variabile).

Un pointer este definit ca o variabilă obișnuită, dar cu un asterisc * plasat înainte de tipul de date. De exemplu, definirea unui pointer pentru un obiect de tip int:

var p *int

Acestui pointer îi putem atribui adresa unei variabile de tip int. Pentru a obține adresa, se folosește operatorul &, urmat de numele variabilei (&x).

package main
 
import "fmt"
 
func main() {
     
    var x int = 4       // definim variabila
    var p *int          // definim pointerul 
    p = &x              // pointerul primește adresa variabilei
    fmt.Println(p)      // valoarea propriului pointer - adresa variabilei x
}

Aici, pointerul p stochează adresa variabilei x. Este important de menționat că variabila x este de tipul int, iar pointerul p indică exact către un obiect de tipul int. Adică trebuie să existe o corespondență între tipuri. Dacă încercăm să afișăm adresa variabilei pe consolă, vom observa că aceasta este un număr în format hexazecimal:

0xc0420120a0

În fiecare caz, adresa poate varia, dar de exemplu, în cazul meu, adresa mașinală a variabilei x este 0xc0420120a0. Adică în memoria computerului există o adresă 0xc0420120a0, unde se află variabila x.

Pe baza adresei stocate de pointer, putem obține valoarea variabilei x. Pentru aceasta, se folosește operația * sau operația de dereferențiere. Rezultatul acestei operații este valoarea variabilei la care pointează pointerul. Vom aplica această operație și vom obține valoarea variabilei x:

package main
 
import "fmt"
 
func main() {
     
    var x int = 4
    var p *int  = &x                // pointerul primește adresa variabilei
    fmt.Println("Address:", p)      // valoarea pointerului - adresa variabilei x
    fmt.Println("Value:", *p)       // valoarea variabilei x
}

Ieșirea în consolă va fi:

Address: 0xc0420c058
Value: 4

De asemenea, folosind pointerul, putem modifica valoarea de la adresa la care acesta indică:

var x int = 4
var p *int = &x
*p = 25
fmt.Println(x)      // 25

Pentru definirea pointerelor se poate folosi și o formă prescurtată:

f := 2.3
pf := &f
     
fmt.Println("Address:", pf)
fmt.Println("Value:", *pf)

Pointerul gol

Dacă unui pointer nu i-a fost atribuită adresa niciunui obiect, atunci acest pointer va avea valoarea implicită nil (adică absența unei valori). Dacă încercăm să obținem valoarea de la un astfel de pointer gol, vom întâmpina o eroare:

var pf *float64
fmt.Println("Value:", *pf)  // ! eroare, pointerul nu indică către niciun obiect

De aceea, atunci când lucrăm cu pointere, uneori este util să verificăm dacă valoarea este nil:

var pf *float64
if pf != nil{
    fmt.Println("Value:", *pf)
}

Funcția new

O variabilă reprezintă un obiect denumit în memorie. Limbajul Go permite și crearea de obiecte anonime - acestea sunt plasate în memorie, dar nu au un nume, așa cum au variabilele. Pentru aceasta se folosește funcția new(type). În această funcție se transmite tipul obiectului care trebuie creat. Funcția returnează un pointer către obiectul creat:

package main
 
import "fmt"
 
func main() {
     
    p := new(int) 
    fmt.Println("Value:", *p)       // Value: 0 - valoarea implicită
    *p = 8                          // modificăm valoarea
    fmt.Println("Value:", *p)       // Value: 8
}

În acest caz, pointerul p va avea tipul *int, deoarece indică către un obiect de tipul int. Obiectul creat va avea valoarea implicită (pentru tipul int aceasta este valoarea 0).

Obiectul creat cu ajutorul funcției new nu diferă cu nimic de o variabilă obișnuită. Singurul lucru este că, pentru a accesa acest obiect - a obține sau modifica adresa acestuia, trebuie folosit un pointer.