Comma Ok İdiom
Bir önceki derste kapalı kanaldan sürekli 0 okuduğumuzu
görmüştük. Kapalı kanallardan veri okuyunca o kanalın tuttuğu türün sıfır
değerini, örneğin int türler için 0 görürüz. Peki bir kanalı okduğumuz
zaman kanaldaki veri gerçekten mi 0 yoksa kapalı bir kanalı okduğumuz için mi
böyle oluyor, bunu nasıl ayıracağız? İşte bunu göreceğiz şimdi.
Aşağıdaki koda bakalım:
package main
import "fmt"
func main() {
ch := make(chan int)
go tx(ch)
rx(ch)
fmt.Println("Çıkış yapıyoruz.")
}
func tx(ch chan<- int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func rx(ch <-chan int) {
i := 0
for {
select {
case v := <-ch:
fmt.Println(v)
}
i += 1
if i > 100 {
return
}
}
}
Bir öncekine benzer bir kod yazdık, sadece tek kanallı. Burada rx() fonksiyonu
tek kanalı aslında dinliyor ve değer oldukça onu tüketiyor. Çıktısı ise şu
şekilde:
0
1
2
3
4
5
6
7
8
9
0
0
.
.
0
İlk başlarda her şey doğru gözükse de tx() tarafından kanal kapatılınca
kanal artık sürekli 0 basıyor ve aslında rx() içerisinde sonsuz bir döngü
oluşuyor. O oluşmasın diye rx() içerisine de bir counter koydum.
Şimdi comma ok idiomu kullanalım:
package main
import "fmt"
func main() {
ch := make(chan int)
go tx(ch)
rx(ch)
fmt.Println("Çıkış yapıyoruz.")
}
func tx(ch chan<- int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func rx(ch <-chan int) {
for {
select {
case v, ok := <-ch:
if ok {
fmt.Println(v)
} else {
fmt.Println("Aa! Kanal kapanmış :(")
return
}
}
}
}
Çıktı:
0
1
2
3
4
5
6
7
8
9
Aa! Kanal kapanmış :(
Çıkış yapıyoruz.
case v, ok := <-ch şeklinde kullanım comma ok idiom olarak geçiyor. Burada
ok değerine bakarak kanaldan okuduğumuz verinin geçerli olup olmadığını
anlıyoruz. Bu kullanımda aslında kanalın kapandığını anlıyoruz ve kapalı
kanaldan okuduğumuz verileri dikkate almıyoruz. Ayrıca rx() fonksiyonumuzun
sonlanması için kullanıyoruz.
Peki Go’da kapanmış kanallar tekrar açılamaz mı? Yaptığım araştırmalara göre hayır. O yüzden kapalı gördüğümüz bir kanalın ömrünün bittiğini düşünebiliriz.