THT DUYURU

Golang Google’a ait insan diline en yakın olan dillerdendir, projelerin ve dökümanların paylaşım alanıdır

Seçenekler

Go 'defer' ~ Al

ALcatraz' - ait Kullanıcı Resmi (Avatar)
Forumdan Uzaklaştırıldı
Üyelik tarihi:
05/2013
Nereden:
İstanbul
Mesajlar:
4.322
Konular:
1030
Teşekkür (Etti):
975
Teşekkür (Aldı):
1818
Ticaret:
(0) %
22-02-2020 17:38
#1
Go 'defer' ~ Al
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:

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("Valentina") fonksiyon return etmeden önce çağrılacak bi listede
   defer fmt.Println("Valentina")

   // Bu satır hemen işleve sokuluyor
   fmt.Println("Retarded")

   // fmt.Println*("Valentina") 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
   }
   file.Close()
   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
    }
    defer file.Close()
    _, err = io.WriteString(file, text)
    if err != nil {
        return err
    }
    return nil
}
Bu sefer şu kod satırlarını ekledik:
Kod:
defer file.Close()
. 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:

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 file.Close()
}
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("tina")
   defer fmt.Println("en")
   defer fmt.Println("Val")
}
Sizce çıktısı ne olacak? Ufak bi' ipucu Last In First Out

Source
Çiçero - ait Kullanıcı Resmi (Avatar)
Co-Admin
Üyelik tarihi:
09/2008
Nereden:
Türk Otağ
Yaş:
37
Mesajlar:
1.235
Konular:
122
Teşekkür (Etti):
679
Teşekkür (Aldı):
537
Ticaret:
(0) %
22-02-2020 17:44
#2
Cevap: Go 'defer' ~ Al
elinize sağlık kardeşim.
---------------------
iletisim [at] turkhackteam [dot] org
'Conqueror - ait Kullanıcı Resmi (Avatar)
Moderatör
Üyelik tarihi:
07/2019
Mesajlar:
1.363
Konular:
138
Teşekkür (Etti):
339
Teşekkür (Aldı):
258
Ticaret:
(0) %
22-02-2020 17:49
#3
Cevap: Go 'defer' ~ Al
Çıktıyı "Valentina" verir.
---------------------
Sen birazcık huzur aradığımda gitmekten en çok hoşlandığım yersin.



PourLa - ait Kullanıcı Resmi (Avatar)
Green Team
Üyelik tarihi:
03/2016
Nereden:
Mesajlar:
1.326
Konular:
282
Teşekkür (Etti):
351
Teşekkür (Aldı):
331
Ticaret:
(0) %
4 Hafta önce
#4
Cevap: Go 'defer' ~ Al
ellerin dert görmesin
---------------------
PourLa
Html/Css > Python > C ve C++
( }-----{ TÜRK HACK TEAM }-----{ )
Twitter | Telegram | İnstagram





Bookmarks


« Önceki Konu | Sonraki Konu »
Seçenekler