Skip to content

Go Pointer

Go pointer'ları korumuştur, bu bir dereceye kadar performansı garanti eder. Aynı zamanda daha iyi GC ve güvenlik düşüncesiyle, pointer kullanımını kısıtlamıştır.

Oluşturma

Pointer ile ilgili iki yaygın operatör vardır: biri adres alma operatörü &, diğeri referanssız hale getirme operatörü *. Bir değişkenin adresini almak, karşılık gelen türün pointer'ını döndürür. Örneğin:

go
func main() {
   num := 2
   p := &num
   fmt.Println(p)
}

Pointer değişken num'ın adresini saklar:

0xc00001c088

Referanssız hale getirme operatörünün iki kullanımı vardır: birincisi pointer'ın işaret ettiği öğeye erişmek, yani referanssız hale getirmek. Örneğin:

go
func main() {
  num := 2
  p := &num
  rawNum := *p
  fmt.Println(rawNum)
}

p bir pointer'dır, pointer türünü referanssız hale getirerek pointer'ın işaret ettiği öğeye erişebilirsiniz. Bir diğer kullanım da bir pointer tanımlamaktır. Örneğin:

go
func main() {
   var numPtr *int
   fmt.Println(numPtr)
}
<nil>

*int bu değişkenin türünün bir int türü pointer'ı olduğunu temsil eder. Ancak pointer sadece tanımlanamaz, başlatılmalıdır. Onun için bellek tahsis etmeniz gerekir, aksi takdirde boş pointer olur ve normal kullanılamaz. Ya adres alma operatörünü kullanarak diğer değişkenlerin adresini bu pointer'a atayın, ya da yerleşik new fonksiyonunu kullanarak manuel olarak tahsis edin. Örneğin:

go
func main() {
   var numPtr *int
   numPtr = new(int)
   fmt.Println(numPtr)
}

Daha çok kısa değişken kullanılır:

go
func main() {
   numPtr := new(int)
   fmt.Println(numPtr)
}

new fonksiyonunun tek parametresi türdür ve karşılık gelen türün pointer'ını döndürür. Fonksiyon bu pointer için bellek tahsis eder ve pointer karşılık gelen türün sıfır değerini işaret eder. Örneğin:

go
func main() {
   fmt.Println(*new(string))
   fmt.Println(*new(int))
   fmt.Println(*new([5]int))
   fmt.Println(*new([]float64))
}

0
[0 0 0 0 0]
[]

Pointer İşlemleri Yasak

Go'da pointer işlemleri desteklenmez, yani pointer kaydırılamaz. Önce bir C++ koduna bakalım:

cpp
int main() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int *p = &arr[0];
    cout << &arr << endl
         << p << endl
         << p + 1 << endl
         << &arr[1] << endl;
}
0x31d99ff880
0x31d99ff880
0x31d99ff884
0x31d99ff884

Dizinin adresi ile dizinin ilk elemanının adresinin aynı olduğu ve pointer'a bir ekleme işlemi yapıldığında, işaret ettiği elemanın dizinin ikinci elemanı olduğu görülebilir. Go'daki dizi de aynıdır, ancak fark pointer'ın kaydırılamamasıdır. Örneğin:

go
func main() {
   arr := [5]int{0, 1, 2, 3, 4}
   p := &arr
   println(&arr[0])
   println(p)
   // pointer işlemi yapmaya çalış
   p++
   fmt.Println(p)
}

Bu tür program derlenemez, hata şu şekildedir:

main.go:10:2: invalid operation: p++ (non-numeric type *[5]int)

TIP

Standart kütüphane unsafe düşük seviyeli programlama için birçok operasyon sağlar, bunlar arasında pointer işlemleri de bulunur. Detaylar için Standart Kütüphane - unsafe adresini ziyaret edin.

new ve make

Önceki birkaç bölümde yerleşik fonksiyonlar new ve make birçok kez anılmıştır. İkisi biraz benzerdir, ancak farklılıklar da vardır. Aşağıda tekrar gözden geçirelim.

go
func new(Type) *Type
  • Dönüş değeri tür pointer'dır
  • Parametre tür alır
  • Sadece pointer için bellek tahsis etmek için kullanılır
go
func make(t Type, size ...IntegerType) Type
  • Dönüş değeri değerdir, pointer değildir
  • İlk parametre türdür, değişken uzunlukta parametre aktarılan türe göre farklıdır
  • Sadece slice, map, channel için bellek tahsis etmek için kullanılır

Aşağıda bazı örnekler verilmiştir:

go
new(int) // int pointer
new(string) // string pointer
new([]int) // int slice pointer
make([]int, 10, 100) // uzunluğu 10, kapasitesi 100 olan int slice
make(map[string]int, 10) // kapasitesi 10 olan map
make(chan int, 10) // buffer boyutu 10 olan channel

Golang by www.golangdev.cn edit