Go'da hataları işlemeyi öğrenin
Programlarınızı yazarken, programlarınızın başarısız olmasının çeşitli yollarını göz önünde bulundurmanız ve hataları yönetmeniz gerekir. Kullanıcılarınızın uzun ve kafa karıştırıcı bir yığın izleme hatası görmesi gerekmez. Neyin yanlış gittiği hakkında anlamlı bilgiler görmeleri daha iyidir. Gördüğünüz gibi, Go'nun programlarınızdaki özel durumları veya beklenmeyen davranışları yönetmek için ve recover
gibi panic
yerleşik işlevleri vardır. Ancak hatalar, programlarınızın işlenecek şekilde derlenmesi gereken bilinen hatalardır.
Go'nun hata işleme yaklaşımı yalnızca bir ve deyiminin gerekli olduğu bir if
return
denetim akışı mekanizmasıdır. Örneğin, bir nesneden bilgi almak için bir employee
işlevi çağırırken çalışanın var olup olmadığını bilmek isteyebilirsiniz. Go'nun bu tür bir beklenen hatayı işlemeye yönelik düşünceli yolu şöyle görünür:
employee, err := getInformation(1000)
if err != nil {
// Something is wrong. Do something.
}
İşlevin yapıyı getInformation
employee
ve ikinci değer olarak bir hatayı nasıl döndürdüğüne dikkat edin. Hata olabilir nil
. Hata ise nil
, bu başarı anlamına gelir. nil
Değilse, bu başarısızlık anlamına gelir. Hata olmayannil
bir hata, yazdırabileceğiniz veya tercihen günlüğe kaydedebileceğiniz bir hata iletisiyle birlikte gelir. Go'da hataları bu şekilde işlersiniz. Sonraki bölümde birkaç stratejiyi daha ele alacağız.
Go'da hata işlemenin, bir hatayı nasıl raporladığınıza ve işlediğinize daha fazla dikkat etmenizi gerektirdiğini fark edeceksiniz. İşte asıl mesele de bu. Go'nun hata işleme yaklaşımını daha iyi anlamanıza yardımcı olacak diğer örneklere göz atalım.
Çeşitli hata işleme stratejileri uygulamak için yapılar için kullandığımız kod parçacığını kullanacağız:
package main
import (
"fmt"
"os"
)
type Employee struct {
ID int
FirstName string
LastName string
Address string
}
func main() {
employee, err := getInformation(1001)
if err != nil {
// Something is wrong. Do something.
} else {
fmt.Print(employee)
}
}
func getInformation(id int) (*Employee, error) {
employee, err := apiCallEmployee(1000)
return employee, err
}
func apiCallEmployee(id int) (*Employee, error) {
employee := Employee{LastName: "Doe", FirstName: "John"}
return &employee, nil
}
Bundan sonra, hataların getInformation
nasıl işleneceğini göstermek için , apiCallEmployee
ve main
işlevlerini değiştirmeye odaklanacağız.
Hata işleme stratejileri
bir işlev hata döndürdüğünde genellikle son dönüş değeri olur. Önceki bölümde gördüğünüz gibi bir hata olup olmadığını denetlemek ve bu hatayı işlemek çağıranın sorumluluğundadır. Bu nedenle yaygın bir strateji, bir alt yordamdaki hatayı yaymak için bu düzeni kullanmaya devam etmektir. Örneğin, bir alt yordam (önceki örnekte olduğu gibi getInformation
) aşağıdaki gibi başka bir şey yapmadan çağırana hata döndürebilir:
func getInformation(id int) (*Employee, error) {
employee, err := apiCallEmployee(1000)
if err != nil {
return nil, err // Simply return the error to the caller.
}
return employee, nil
}
Hatayı yaymadan önce daha fazla bilgi de eklemek isteyebilirsiniz. Bu amaçla, daha önce gördüğümüze benzer ancak bir hata döndüren işlevini kullanabilirsiniz fmt.Errorf()
. Örneğin, hataya daha fazla bağlam ekleyebilir ve yine de aşağıdaki gibi özgün hatayı döndürebilirsiniz:
func getInformation(id int) (*Employee, error) {
employee, err := apiCallEmployee(1000)
if err != nil {
return nil, fmt.Errorf("Got an error when getting the employee information: %v", err)
}
return employee, nil
}
Bir diğer strateji de hatalar geçici olduğunda yeniden deneme mantığını çalıştırmaktır. Örneğin, bir işlevi üç kez çağırmak ve aşağıdaki gibi iki saniye beklemek için yeniden deneme ilkesi kullanabilirsiniz:
func getInformation(id int) (*Employee, error) {
for tries := 0; tries < 3; tries++ {
employee, err := apiCallEmployee(1000)
if err == nil {
return employee, nil
}
fmt.Println("Server is not responding, retrying ...")
time.Sleep(time.Second * 2)
}
return nil, fmt.Errorf("server has failed to respond to get the employee information")
}
Son olarak, hataları konsola yazdırmak yerine hataları günlüğe kaydedebilir ve uygulama ayrıntılarını son kullanıcılardan gizleyebilirsiniz. Sonraki modülde günlüğe kaydetmeyi ele alacağız. Şimdilik özel hataları nasıl oluşturabileceğinize ve kullanabileceğinize bakalım.
Yeniden kullanılabilir hatalar oluşturma
Bazen hata iletilerinin sayısı artar ve düzeni korumak istersiniz. Veya yeniden kullanmak istediğiniz yaygın hata iletileri için bir kitaplık oluşturmak isteyebilirsiniz. Go'da, hata oluşturmak ve bunları aşağıdaki gibi birkaç bölümde yeniden kullanmak için işlevini kullanabilirsiniz errors.New()
:
var ErrNotFound = errors.New("Employee not found!")
func getInformation(id int) (*Employee, error) {
if id != 1001 {
return nil, ErrNotFound
}
employee := Employee{LastName: "Doe", FirstName: "John"}
return &employee, nil
}
İşlevin getInformation
kodu daha iyi görünür ve hata iletisini değiştirmeniz gerekirse, bunu tek bir yerde yaparsınız. Ayrıca, kuralın hata değişkenleri için ön ek eklemek Err
olduğuna dikkat edin.
Son olarak, bir hata değişkeniniz olduğunda, çağıran işlevindeki bir hatayı işlerken daha belirgin olabilirsiniz. işlevi, errors.Is()
aşağıdaki gibi, almakta olduğunuz hata türünü karşılaştırmanıza olanak tanır:
employee, err := getInformation(1000)
if errors.Is(err, ErrNotFound) {
fmt.Printf("NOT FOUND: %v\n", err)
} else {
fmt.Print(employee)
}
Hata işleme için önerilen uygulamalar
Go'daki hataları işlerken göz önünde bulundurmanız gereken bazı önerilen uygulamalar şunlardır:
- Hataları beklemeseniz bile her zaman denetleyin. Ardından, gereksiz bilgilerin son kullanıcılara açık olmasını önlemek için bunları düzgün bir şekilde işleyin.
- Hatanın kaynağını bilmeniz için hata iletisine bir ön ek ekleyin. Örneğin, paketin ve işlevin adını ekleyebilirsiniz.
- Mümkün olduğunca yeniden kullanılabilir hata değişkenleri oluşturun.
- Geri dönen hataları kullanma ile panikleme arasındaki farkı anlayın. Yapabileceğin başka bir şey olmadığında panik yap. Örneğin, bir bağımlılık hazır değilse, programın çalışması mantıklı değildir (varsayılan bir davranış çalıştırmak istemiyorsanız).
- Mümkün olduğunca çok ayrıntı içeren hataları günlüğe kaydetme (sonraki bölümde nasıl yapılacağını ele alacağız) ve son kullanıcının anlayabileceği hataları yazdırın.