x.(T): değeri bir interface'ten çıkarmak
Bir interface değeri tuttuğu somut tipi gizler. Bir type assertion x.(T) onu geri ister.
Çıktı:
gopher 6
0 false
string of length 6
x'in bir interface tipi olmalıdır. Somut bir tip üzerinde assertion derlenmez: invalid operation: s (variable of type string) is not an interface.
Tek değerli biçim panic olur
Assertion yanlış olduğunda tek değerli biçim, iki tipi de adlandıran bir mesajla panic olur:
Çıktı:
recovered: interface conversion: interface {} is int, not string
Tek değerli biçimi yalnızca farklı bir tipin, çökmesini istediğiniz bir programlama hatası olacağı durumlarda kullanın. Diğer her yerde virgül-ok kullanın. Başarısızlıkta virgül-ok, T'nin sıfır değerini ve false verir.
Nil bir interface üzerinde assertion da başarısız olur: var v any; v.(string), interface conversion: interface {} is nil, not string ile panic olur, virgül-ok biçimi ise "", false döndürür.
Başka bir interface'e assertion
T bir interface tipi olabilir. Assertion bu durumda dinamik değer T'yi gerçekleştiriyorsa başarılı olur ve sonuç aynı dinamik değeri korur. Standart kütüphane isteğe bağlı yetenekleri böyle kontrol eder.
io.Copy, kaynağının io.WriterTo'yu gerçekleştirip gerçekleştirmediğini kontrol eder ve gerçekleştiriyorsa onu kullanır. fmt, Stringer ve error'u kontrol eder. Bu kalıp, küçük bir interface'in küçük kalmasını sağlarken çağıranların daha zengin gerçekleştirmelerden yararlanmasına da izin verir.
Type switch
Bir değer birkaç tipten biri olabildiğinde bir type switch, assertion zincirinin yerini alır. x.(type) yalnızca bir switch içinde geçerlidir.
Çıktı:
hi
integer 7
integer 8
3.14
nil
error: boom
unhandled []int
Bilmeye değer kurallar:
- Tek tipli bir case'te
xo tipe sahiptir. Birkaç tip listeleyen bir case'te vedefault'taxorijinal interface'in tipine (buradaany) sahiptir. - Case'ler sırayla kontrol edilir. Bir değer birkaç interface'i karşılayabileceği için daha belirli interface'leri daha genişlerden önce koyun.
case nilyalnızca nil bir interface ile eşleşir, nil bir pointer tutan bir interface ile değil.- Bir type switch'te
fallthroughyoktur.
errors.As: sarmalanmış hatalar için assertion
Hatalar çoğu zaman bağlamla sarmalanır: fmt.Errorf("load config: %w", err). Doğrudan bir type assertion yalnızca en dıştaki hataya bakar ve içtekini kaçırır. errors.As zinciri dolaşır.
Çıktı:
type assertion finds it: false
errors.As finds it: open /no/such/file
Hatalar üzerinde type assertion'ı yalnızca hatanın sarmalanmadığını bildiğinizde kullanın; bu da pratikte neredeyse hiçbir zaman demektir. errors.As, errors.Is ve kendi hata tiplerinizi tanımlamayı özel hatalar sayfası anlatıyor.
Assertion'lar, dönüşümler ve generics
| Elinizdeki | İstediğiniz | Kullanın |
|---|---|---|
int | float64 | dönüşüm: float64(n) |
bir int tutan any | int'in kendisi | assertion: v.(int) |
olası birkaç tipten biri olan any | tipe göre dallanmak | type switch |
sarmalanmış olabilecek bir error | belirli bir hata tipi | errors.As |
| birçok tip için çalışan bir fonksiyon | derleme zamanı güvenliği | generics |
any ve type switch'lerle dolu kod çoğu zaman generics'in ya da düzgün bir interface'in niyeti daha iyi ifade edeceğine ve hataları derleme zamanında yakalayacağına işarettir.
Sık yapılan hatalar
- Güvenilmeyen veride panic yapan biçimi kullanmak. Çözülmüş JSON,
anytipindeki map değerleri, eklenti girdileri: her zaman virgül-ok. - Yanlış sayısal tipe assertion. JSON sayıları
anyiçinefloat64olarak çözülür, bu yüzdenv.(int)onlarda başarısız olur. - Pointer saklanmışken değer tipine assertion. Interface
*Usertutuyorsav.(User)başarısız olur.v.(*User)ile assertion yapın. - Hatalar üzerinde type assertion.
errors.Askullanın.
Sıkça Sorulan Sorular
Go'da type assertion nedir?
x'in bir interface değeri olduğu x.(T) ifadesidir. T somut bir tipse x içinde saklanan değeri bir T olarak döndürür. T bir interface tipiyse saklanan değerin T'yi de gerçekleştirdiğini kontrol eder. Tek değerli biçim kontrol başarısız olduğunda panic olur; iki değerli biçim v, ok := x.(T) bunu ok içinde bildirir.
Go'da bir interface değerinin tipi nasıl kontrol edilir?
Bir type switch kullanın: switch v := x.(type) { case int: ...; case string: ...; default: ... }. Her case içinde v o case'in tipine sahiptir. Tek bir tip için virgül-ok assertion'ı s, ok := x.(string) daha kısadır. fmt.Printf("%T", x) hata ayıklama için tip adını yazdırır.
Go'da type assertion ile tip dönüşümü arasındaki fark nedir?
Bir dönüşüm T(x), float64(n) gibi bir tipteki değeri başka bir tipe çevirir; izin verilip verilmediğine derleyici karar verir ve çalışma zamanında başarısız olamaz. Bir assertion x.(T) yalnızca interface değerleri üzerinde çalışır ve içinde hangi tipin saklandığını çalışma zamanında kontrol eder. Bir int tutan any için int(x) yazamazsınız; x.(int) gerekir.
Hata tiplerini kontrol etmek için type assertion kullanmalı mıyım?
Hayır. errors.As(err, &target) kullanın. Doğrudan bir assertion err.(*MyError) yalnızca en dıştaki hataya bakar, bu yüzden hata fmt.Errorf("...: %w", err) ile sarmalandığı anda başarısız olur. errors.As sarmalama zincirini dolaşır.