Go'da değişken tanımlamanın iki yolu vardır: her yerde çalışan var ve fonksiyonların içinde çalışıp tipi çıkaran kısa biçim :=.
Her değişkenin derleme zamanında belirlenen sabit bir tipi vardır. Bir değer verdiğinizde Go tipi o değerden çıkarır, bu yüzden tipi ayrıca yazmak (var city string = "Lisbon") geçerlidir ama gereksizdir.
var ve :=
var | := | |
|---|---|---|
| Nerede | paket seviyesinde ve fonksiyonların içinde | yalnızca fonksiyonların içinde |
| Tip | isteğe bağlı; değer yoksa zorunlu | her zaman çıkarılır |
| İlk değer | isteğe bağlı (yoksa sıfır değer) | zorunlu |
| Yeniden tanımlama | asla | soldaki değişkenlerden en az biri yeniyse izinli |
Bir fonksiyonun içinde deyimsel seçim:
- Bir başlangıç değeriniz varsa
x := value. - Sıfır değeri, yani "bilerek boş" olduğunu belirtmek istediğinizde
var x T:var buf bytes.Buffer,var total int. - Çıkarılan tip istediğiniz tip değilse
var x T = value, örneğinvar ratio float64 = 1(düzratio := 1birintolurdu).
Fonksiyon dışında := bir söz dizimi hatasıdır:
./main.go:5:1: syntax error: non-declaration statement outside function body
Sıfır Değerler
Değer verilmeden tanımlanan bir değişken asla çöp değer taşımaz. Tipinin sıfır değerini tutar:
| Tip | Sıfır değer |
|---|---|
| tam sayılar, ondalıklı sayılar | 0 |
bool | false |
string | "" |
| pointer'lar, slice'lar, map'ler, channel'lar, fonksiyonlar, interface'ler | nil |
| diziler, struct'lar | her eleman ya da alan kendi sıfır değerinde |
İyi Go API'leri sıfır değer işe yarayacak şekilde tasarlanır: sıfır değerli bir sync.Mutex kilitli değildir, sıfır değerli bir bytes.Buffer boştur ve kullanıma hazırdır, len, range ve append nil bir slice üzerinde çalışır. Dikkat edilmesi gereken map'tir: nil bir map'ten okumak sıfır değerler döndürür, ama ona yazmak panic'e yol açar. İçine bir şey koymadan önce map'leri make ile ya da bir literal ile oluşturun.
Birden Fazla Değişken Tanımlamak
var ( ... ) bloğu ilişkili paket seviyesi değişkenleri gruplar. x, y = y, x gibi bir çoklu atamada sağdaki her ifade herhangi bir atama yapılmadan önce değerlendirilir; takasın çalışmasının nedeni budur.
Birden fazla adla kullanılan :=, soldaki adlardan en az biri yeni olduğu sürece hiçbir şeyi yeniden tanımlamaz. Aynı kapsamda zaten var olan adlara yalnızca atama yapılır. err'i yeniden kullanmanızı sağlayan budur:
f, err := os.Open("a.txt") // declares f and err
g, err := os.Open("b.txt") // declares g, assigns to the existing err
Adların hiçbiri yeni değilse bu bir hatadır:
./main.go:7:4: no new variables on left side of :=
Zaten var olan bir değişkene atama yapmak için düz = kullanın.
Kullanılmayan Değişkenler Hatadır
Tanımlanıp hiç okunmayan yerel bir değişken derlemeyi durdurur:
./main.go:9:2: declared and not used: x
Bu, kapatabileceğiniz bir uyarı değildir. Değişkeni silin, kullanın ya da hata ayıklarken boş tanımlayıcıyla susturun: _ = x. Boş tanımlayıcı ihtiyacınız olmayan dönüş değerlerini de atar: _, err := fmt.Println("hi").
Paket seviyesindeki değişkenler ve fonksiyon parametreleri bu kuralın dışındadır.
Kapsam ve Gölgeleme
Bir değişken, tanımlandığı yerden onu içeren bloğun ({ ... }) sonuna kadar vardır. İç bir bloktaki :=, dışarıda aynı adda bir değişken olsa bile yeni bir değişken oluşturur. Dıştaki değişken değişmez, gölgelenir:
Program önce inside: 42, sonra outside: 0 yazdırır. if içindeki :=, iç blokta henüz ikisi de olmadığı için hem count'u hem de err'i yeni değişkenler olarak tanımladı. Kod sorunsuz derlenir ve klasik bir "değerim kayboldu" hatası kaynağıdır.
Çözüm, önce err'i tanımlamak ve = ile atamaktır:
var err error
count, err = strconv.Atoi(input)
go vet varsayılan olarak gölgelemeyi raporlamaz. Ayrı shadow analizcisi raporlar, golangci-lint gibi linter'lar da onu etkinleştirebilir.
Adlandırma
camelCasekullanın:maxRetries,userID.max_retriesdeğil.- Kısaltmaları tek harf büyüklüğünde tutun:
userID,httpClient,parseURL;userIddeğil. - Kısa kapsamlar için kısa adlar: döngüde
i, reader içinr, hata içinerr. Paket seviyesindeki değişkenler için daha uzun, açıklayıcı adlar. - Paket seviyesinde büyük harfle başlayan bir ad (
var Timeout) diğer paketlere dışa açılır. Paketler ve import'lar sayfasına bakın.
Paket Seviyesindeki Değişkenler
Fonksiyonların dışında tanımlanan değişkenler programın tamamı boyunca yaşar ve main çalışmadan önce, bağımlılık sırasına göre başlatılır. Yapılandırma ve önbellekler için kullanışlıdırlar ve tüm goroutine'ler tarafından paylaşılırlar. Birden fazla goroutine birine yazıyorsa onu bir mutex ile koruyun ya da sync/atomic kullanın; aksi halde bir data race oluşur.
Hiç değişmeyen değerler için sabitleri tercih edin. Bir const yanlışlıkla değiştirilemez ve çalışma zamanında hiçbir maliyeti yoktur.
Sıkça Sorulan Sorular
Go'da var ile := arasındaki fark nedir?
:= bir değişkeni tipini çıkararak tanımlar ve ilk değerini verir; yalnızca fonksiyonların içinde çalışır: count := 10. var her yerde çalışır (paket seviyesi dahil), tipi belirtmenize izin verir ve sıfır değeri almak için ilk değeri atlayabilir: var count int. Fonksiyonların içinde deyimsel Go, bir ilk değer varken :=, sıfır değer istendiğinde var kullanır.
Go'da sıfır değerler nedir?
Değer verilmeden tanımlanan her değişken kendi tipinin sıfır değerini alır: sayılar için 0, bool için false, string için "", pointer'lar, slice'lar, map'ler, channel'lar, fonksiyonlar ve interface'ler için nil. Struct'lar her alanın sıfır değerini alır. Go'da ilk değeri verilmemiş değişken yoktur.
Go'da "declared and not used" hatası nasıl düzeltilir?
Go, atanıp hiç okunmayan yerel bir değişkeni reddeder. Onu kullanın, silin ya da hata ayıklarken _ = x ile boş tanımlayıcıya atayın. Paket seviyesindeki değişkenler ve fonksiyon parametreleri bu kuralın dışındadır.
Go'da global değişken nasıl tanımlanır?
Herhangi bir fonksiyonun dışında, paket seviyesinde var kullanın: var counter int. Kısa := biçimine orada izin verilmez. Büyük harfle başlayan bir ad (var Counter int) diğer paketlere görünür; küçük harfle başlayan yalnızca kendi paketinde görünür. Goroutine'ler paket seviyesindeki değişkenlere yazıyorsa onları bir mutex ile koruyun.