Go, diğer programlama dillerinde yaygın olarak kullanılan kontrol akışı keywordlerinin çoğunu içerir; ör. "if", "switch", "for" gibi. Diğer programlama dillerinde bulunmayan bir keyword "defer" dir. Daha az sıklıkta olsa bile, programlarınızda ne kadar yararlı olabileceğini hızlı bir şekilde göreceksiniz.
Bir "+defer" ifadesinin ana kullanımlarından biri, açık dosyalar, ağ bağlantıları ve database-handles gibi kaynakları temizlemektir. Programınız bu kaynaklarla tamamlandığında, program sınırlarını tüketmemek ve diğer programların bu kaynaklara erişmesine izin vermemek için bunları kapatmamız gerekir. `defer ', açık çağrının yakınında dosyayı / kaynağı kapatmak için çağrıları tutarak kodumuzu daha temiz ve hatalara daha az eğilimli yapar.
Bu makalede, kaynakları temizlemek için "defer" keyword'ünün nasıl kullanılacağını ve "defer" kullanılırken sık karşılaşılan bazı hataların nasıl çözüleceğini göreceğiz.Stack'e yapılan tüm çağrılar, eklendiği işlev döndüğünde çağrılır. Aramalar bir stacküzerinde depolandığından, son giriş ve ilk çıkış sırasıyla çağrılır.
En basit örneklerinden Println fonksiyonu ve "defer" işleminin nasıl çalıştığını görelim:
Main fonksiyonumuz'da defer keyword'ü ile başlayan Println fonksiyonumuz 'Valentina' çıktısını veriyor. Onu takip eden Println fonksiyonumuzda ise 'Retarded' çıktısını veriyor. Normalde ilk Println fonksiyonumuz Valentina'yı vermesi gerekirken çalıştırdığımızda şu şekilde bir çıktı görürüz;
Şimdi de bir kaç yorum satırı ekleyip kodumuzu anlamlandırmaya çalışalım;
"defer" yi anlamanın kısa yolu, erteleme işlevi için bağımsız değişkenlerin "defer" deyimi yürütüldüğünde hemen değerlendirilmesidir. Bir defer `yürütüldüğünde, işlev geri gelmeden önce çağrılması gereken aşağıdaki ifadeyi bir listeye yerleştirir.
Bu kod "defer" nin yürütüldüğü sırayı temsil etse de, bu bir Go programı yazmak için tipik bir yol değildir. Dosya tanıtıcısı gibi bir kaynağı temizlemek için `defer 'kullanmamız daha olasıdır. Nasıl çalıştığını görelim.
Bu programda, ilk olarak bir dosya oluşturmaya çalışan "write" adlı bir fonksiyon vardır. Bir hata varsa, hata döndürülür ve fonksiyon sonlandırılır. Ardından, belirtilen dosyaya "This is a readme file" text'i yazma girişiminde bulunuldu. Bir hata oluşursa, hata döndürülür ve fonksiyon sona erer. Fonksiyon daha sonra dosyayı kapatmaya ve kaynağı sisteme geri bırakmaya çalışır. Son olarak, fonksiyonun hatasız yürütüldüğünü belirtmek için "nil" fonksiyonu döndürür.
Bu kod çalışmasına rağmen,bir hata var. "io.WriteString" çağrısı başarısız olursa, fonksiyon dosyayı kapatmadan ve kaynağı sisteme döndürmeden geri döner.
Başka bir file.Close() ifadesi ekleyerek sorunu çözebiliriz. Yani bunu defer olmadan da çözersiniz:
"io.WriteString" çağrısı başarısız olsa bile dosya hala kapalıdır. Bu, daha karmaşık bir fonksiyon olan bir hata tespit etmek ve düzeltmek nispeten kolay olsa da, gözden kaçırılmış olabilir.
"file.Close()" öğesine ikinci çağrıyı eklemek yerine, yürütme sırasında hangi dalların kullanıldığından bağımsız olarak "Close()" öğesinin her zaman çağrıldığından emin olmak için bir "defer" ifadesi kullanabiliriz.
"defer" keyword'ünü kullanalım:
Bu sefer şu kod satırlarını ekledik:
. Bu derleyiciye write fonksiyonundan çıkmadan önce file.Close() 'yı yürütmesini söyler. Gelecekte daha fazla kod eklesek ve fonksiyonu bırakan başka bir dal oluştursak bile dosyayı temizleyip kapatmamızı sağladık.
Ancak deferekleyerek başka bir hata daha ekledik. Artık "Close" yöntemiyle döndürülebilecek olası hatayı kontrol etmiyoruz. Bunun nedeni, "defer" kullanılırken fonksiyonumuza bir dönüş değeri döndürmenin bir yolu olmamasıdır.
Go, programınızın davranışını etkilemeden Close() öğesini birden çok kez çağırmanın güvenli ve kabul edilmiş bir yöntem olduğunu düşünür. Close() bir hata döndürürse, bu ilk çağrıldığında yapılır. Bu, onu başarılı yürütme yolunda açıkça işlevimize çağırmamızı sağlar.
"Close" çağrısını nasıl erteleyebileceğimize bakalım ve bir tanesiyle karşılaştığımızda bir hata raporlayalım:
Bu programdaki tek değişiklik, file.Close() döndürdüğümüz son satırdır. Close çağrısı bir hataya yol açarsa, bu artık beklendiği gibi returnfonskiyonuna geri döner. defer file.Close() ifadesinin de return ifadesinden sonra yürütüldüğünü unutmayın. Bu, file.Close() öğesinin iki kez çağrılabileceği anlamına gelir. Bu ideal olmasa da, programınız üzerinde herhangi bir yan etkiye neden olmaması gerektiği için kabul edilebilir bir eylem şeklidir.
Ancak, fonksiyonda daha önce bir hata oluşursa, ör. "WriteString" çağrılırken, fonksiyon bu hatayı döndürür ve ertelendiği için "file.Close" işlevini çağırmaya çalışır. `File.Close'' bir hata döndürse de (ve muhtemelen de), artık ilgilenmiyoruz çünkü başlangıçta neyin yanlış gittiğini bize söyleyen bir hata aldık. Şimdiye kadar tek bir gecikmeyle kaynaklarımızı düzgün bir şekilde temizlememizi nasıl sağlayabileceğimizi gördük. Daha sonra, birden fazla kaynağı temizlemek için birden fazla defer ifadesini nasıl kullanabileceğimizi göreceğiz.
Bir fonksiyonun birden fazla "defer" ifadesi içermesi normaldir. Çoklu defer uyguladığımızda ne olacağını görmek için sadece "defer" talimatlarını içeren bir program oluşturalım:
Sizce çıktısı ne olacak? Ufak bi' ipucu Last In First Out
Source
Bir "+defer" ifadesinin ana kullanımlarından biri, açık dosyalar, ağ bağlantıları ve database-handles gibi kaynakları temizlemektir. Programınız bu kaynaklarla tamamlandığında, program sınırlarını tüketmemek ve diğer programların bu kaynaklara erişmesine izin vermemek için bunları kapatmamız gerekir. `defer ', açık çağrının yakınında dosyayı / kaynağı kapatmak için çağrıları tutarak kodumuzu daha temiz ve hatalara daha az eğilimli yapar.
Bu makalede, kaynakları temizlemek için "defer" keyword'ünün nasıl kullanılacağını ve "defer" kullanılırken sık karşılaşılan bazı hataların nasıl çözüleceğini göreceğiz.Stack'e yapılan tüm çağrılar, eklendiği işlev döndüğünde çağrılır. Aramalar bir stacküzerinde depolandığından, son giriş ve ilk çıkış sırasıyla çağrılır.
En basit örneklerinden Println fonksiyonu ve "defer" işleminin nasıl çalıştığını görelim:
Kod:
package main
import "fmt"
func main() {
defer fmt.Println("Valentina")
fmt.Println("Retarded")
}
Main fonksiyonumuz'da defer keyword'ü ile başlayan Println fonksiyonumuz 'Valentina' çıktısını veriyor. Onu takip eden Println fonksiyonumuzda ise 'Retarded' çıktısını veriyor. Normalde ilk Println fonksiyonumuz Valentina'yı vermesi gerekirken çalıştırdığımızda şu şekilde bir çıktı görürüz;
Kod:
'Retarded
Valentina'
Şimdi de bir kaç yorum satırı ekleyip kodumuzu anlamlandırmaya çalışalım;
Kod:
package main
import "fmt"
func main() {
// defer ifadesi yürütülüyor
// fmt.Println("[COLOR="white"]Valentina[/COLOR]") fonksiyon return etmeden önce çağrılacak bi listede
defer fmt.Println("[COLOR="white"]Valentina[/COLOR]")
// Bu satır hemen işleve sokuluyor
fmt.Println("Retarded")
// fmt.Println*("[COLOR="white"]Valentina[/COLOR]") Fonksiyonun sonuna geldiğimiz için defer ile tanımladığımız işlev çağrılıyor
}
"defer" yi anlamanın kısa yolu, erteleme işlevi için bağımsız değişkenlerin "defer" deyimi yürütüldüğünde hemen değerlendirilmesidir. Bir defer `yürütüldüğünde, işlev geri gelmeden önce çağrılması gereken aşağıdaki ifadeyi bir listeye yerleştirir.
Bu kod "defer" nin yürütüldüğü sırayı temsil etse de, bu bir Go programı yazmak için tipik bir yol değildir. Dosya tanıtıcısı gibi bir kaynağı temizlemek için `defer 'kullanmamız daha olasıdır. Nasıl çalıştığını görelim.
Kod:
package main
import (
"io"
"log"
"os"
)
func main() {
if err := write("readme.txt", "This is a readme file"); err != nil {
log.Fatal("failed to write file:", err)
}
}
func write(fileName string, text string) error {
file, err := os.Create(fileName)
if err != nil {
return err
}
_, err = io.WriteString(file, text)
if err != nil {
return err
}
file.Close()
return nil
}
Bu programda, ilk olarak bir dosya oluşturmaya çalışan "write" adlı bir fonksiyon vardır. Bir hata varsa, hata döndürülür ve fonksiyon sonlandırılır. Ardından, belirtilen dosyaya "This is a readme file" text'i yazma girişiminde bulunuldu. Bir hata oluşursa, hata döndürülür ve fonksiyon sona erer. Fonksiyon daha sonra dosyayı kapatmaya ve kaynağı sisteme geri bırakmaya çalışır. Son olarak, fonksiyonun hatasız yürütüldüğünü belirtmek için "nil" fonksiyonu döndürür.
Bu kod çalışmasına rağmen,bir hata var. "io.WriteString" çağrısı başarısız olursa, fonksiyon dosyayı kapatmadan ve kaynağı sisteme döndürmeden geri döner.
Başka bir file.Close() ifadesi ekleyerek sorunu çözebiliriz. Yani bunu defer olmadan da çözersiniz:
Kod:
package main
import (
"io"
"log"
"os"
)
func main() {
if err := write("readme.txt", "This is a readme file"); err != nil {
log.Fatal("failed to write file:", err)
}
}
func write(fileName string, text string) error {
file, err := os.Create(fileName)
if err != nil {
return err
}
_, err = io.WriteString(file, text)
if err != nil {
return err
}
[COLOR="yellowgreen"]file.Close()[/COLOR]
return nil
}
"io.WriteString" çağrısı başarısız olsa bile dosya hala kapalıdır. Bu, daha karmaşık bir fonksiyon olan bir hata tespit etmek ve düzeltmek nispeten kolay olsa da, gözden kaçırılmış olabilir.
"file.Close()" öğesine ikinci çağrıyı eklemek yerine, yürütme sırasında hangi dalların kullanıldığından bağımsız olarak "Close()" öğesinin her zaman çağrıldığından emin olmak için bir "defer" ifadesi kullanabiliriz.
"defer" keyword'ünü kullanalım:
Kod:
package main
import (
"io"
"log"
"os"
)
func main() {
if err := write("readme.txt", "This is a readme file"); err != nil {
log.Fatal("failed to write file:", err)
}
}
func write(fileName string, text string) error {
file, err := os.Create(fileName)
if err != nil {
return err
}
[COLOR="yellowgreen"]defer file.Close()[/COLOR]
_, err = io.WriteString(file, text)
if err != nil {
return err
}
return nil
}
Bu sefer şu kod satırlarını ekledik:
Kod:
defer file.Close()
Ancak deferekleyerek başka bir hata daha ekledik. Artık "Close" yöntemiyle döndürülebilecek olası hatayı kontrol etmiyoruz. Bunun nedeni, "defer" kullanılırken fonksiyonumuza bir dönüş değeri döndürmenin bir yolu olmamasıdır.
Go, programınızın davranışını etkilemeden Close() öğesini birden çok kez çağırmanın güvenli ve kabul edilmiş bir yöntem olduğunu düşünür. Close() bir hata döndürürse, bu ilk çağrıldığında yapılır. Bu, onu başarılı yürütme yolunda açıkça işlevimize çağırmamızı sağlar.
"Close" çağrısını nasıl erteleyebileceğimize bakalım ve bir tanesiyle karşılaştığımızda bir hata raporlayalım:
Kod:
package main
import (
"io"
"log"
"os"
)
func main() {
if err := write("readme.txt", "This is a readme file"); err != nil {
log.Fatal("failed to write file:", err)
}
}
func write(fileName string, text string) error {
file, err := os.Create(fileName)
if err != nil {
return err
}
defer file.Close()
_, err = io.WriteString(file, text)
if err != nil {
return err
}
return [COLOR="YellowGreen"]file.Close()[/COLOR]
}
Bu programdaki tek değişiklik, file.Close() döndürdüğümüz son satırdır. Close çağrısı bir hataya yol açarsa, bu artık beklendiği gibi returnfonskiyonuna geri döner. defer file.Close() ifadesinin de return ifadesinden sonra yürütüldüğünü unutmayın. Bu, file.Close() öğesinin iki kez çağrılabileceği anlamına gelir. Bu ideal olmasa da, programınız üzerinde herhangi bir yan etkiye neden olmaması gerektiği için kabul edilebilir bir eylem şeklidir.
Ancak, fonksiyonda daha önce bir hata oluşursa, ör. "WriteString" çağrılırken, fonksiyon bu hatayı döndürür ve ertelendiği için "file.Close" işlevini çağırmaya çalışır. `File.Close'' bir hata döndürse de (ve muhtemelen de), artık ilgilenmiyoruz çünkü başlangıçta neyin yanlış gittiğini bize söyleyen bir hata aldık. Şimdiye kadar tek bir gecikmeyle kaynaklarımızı düzgün bir şekilde temizlememizi nasıl sağlayabileceğimizi gördük. Daha sonra, birden fazla kaynağı temizlemek için birden fazla defer ifadesini nasıl kullanabileceğimizi göreceğiz.
Bir fonksiyonun birden fazla "defer" ifadesi içermesi normaldir. Çoklu defer uyguladığımızda ne olacağını görmek için sadece "defer" talimatlarını içeren bir program oluşturalım:
Kod:
package main
import "fmt"
func main() {
defer fmt.Println("[COLOR="white"]tina[/COLOR]")
defer fmt.Println("[COLOR="white"]en[/COLOR]")
defer fmt.Println("[COLOR="white"]Val[/COLOR]")
}
Sizce çıktısı ne olacak? Ufak bi' ipucu Last In First Out
Source