2013-10-29 31 views
6

Gitme zamanı, panic(nil) algılayabilir ve bir hata bildirir.Panik (nil) ve ertelenmiş işlevdeki normal yürütme nasıl algılanır?

Ancak nil verdiği için, bir defer kırmızı işlevinde recover() ile panic(nil) tespit edemez, böylece recover() dönüş değer sıfır I için test etmek gibi normal çalıştırma (panik) ayırt edilemez . Örneğin

,

defer func(){ 
    var err = recover() 
    if err != nil { 
     // Real serious situation. Panic from inner code. 
     // And we may have some critical resources which 
     // must be cleaned-up at any cases. 
     // However, this will not be executed for panic(nil) 

     rollback() 

     // I am still not sure that how should I treat `panic`… 
     // Should I just ignore them? 
    } 
}() 

var err = doTransaction() 
if err == nil { 
    commit() // Happy case. 
} else { 
    rollback() // Regular execution. Just a lucky case. 
} 

ROLLBACK sadece bir örnektir ve ben kritik durumlarda bol temizleme ihtiyacı olabilir düşünüyorum. Peki, bu temizleme kodu gerçek program çökmesine de uygulanmayacak, ancak olabildiğince savunmak istiyorum.

Parametresinden bağımsız olarak ertelenmiş bir işlevdeki herhangi bir paniği nasıl algılayabilirim?

cevap

4

Sorunuzu yanlış anlamadıkça, ertelenmiş işlev çağrıları, nil geçirilen değer olsa bile panik yaparken yayınlanacak. Bu following program tarafından tasvir edilmektedir: panic(nil)nil için recover() tarafından döndürülen değeri karşılaştırarak olduysa

package main 

import "fmt" 

func main() { 
    defer func() { 
     fmt.Println("Recover:", recover()) 
    }() 
    panic(nil) 
} 

Bu nedenle kolaylıkla algılayabilir.

Düzenleme yorumunu cevap:

Evet, bu doğru; ertelenmiş çağrılar normalde bir işlev döndüğünde çalışır. Ancak, çağrı yığınını panic()'dan sonra açarken de çalışırlar. sorudan sonra

Düzenleme güncellendi:

Haklısın bu davaları ayırt etmek yolu yoktur söyledi. Öte yandan, nil ile panik yapmak da pek mantıklı değil - özellikle bu sınırlama nedeniyle.

panic(nil) için düşünebildiğim tek kullanım vakası, kurtarma işleminden kasıtlı olarak kaçınmak ve programın bir yığın izi ile çökmesine zorlamak olacaktır. Bunun için runtime paketini kullanarak daha şık yollar vardır.

+0

Belirsiz bir soru için üzgünüm. İstediğim şey, 'panik (nil)' ve 'normal işlev' işlevini ertelemekti… – Eonil

+0

Belki de fonksiyondan çıkmadan önce bir bayrak ayarlayabilirim. – Eonil

+0

İlham için teşekkürler! Bunu bir bayrak ayarlayarak çözdüm. – Eonil

2

Çıkmadan önce bir bayrak ayarlayabilirim. AFAIK, panik, goroutine özgüdür ve tek bir üründe tek bir goroutinin olduğu garanti edilmektedir. Yani ok değişkeninin etrafında senkronizasyon/kilitleme gerekli değildir. Eğer yanılıyorsam, lütfen beni düzeltin.

func clean(ok *bool) { 
    if *ok { 
     log.Printf("Execution OK. No panic detected.\n") 
    } else { 
     var reason = recover() 
     log.Printf("Some bad thing happen. reason = %v\n", reason) 
     panic("Abnormal exit. Program abandoned. Stack-trace here.") 
     debug.PrintStack() // Oops. this will not run. 
    } 
} 

func main() { 
    var ok bool = false 

    defer clean(&ok) 
    panic(nil) 

    test1() // Here's the main job. 

    ok = true 
    log.Printf("All work done. Quit gracefully.\n") 
} 
+0

Hata işleme konusundaki son çare olan ** panik ** 'nin bekleyip artmayacağına karar veren bir işaretin kullanılması nedir? Gerçekte ne elde etmeye çalışıyorsunuz? Bu birçok düzeyde yanlış görünüyor. – nemo

+0

@nemo Benim durumumda, herhangi bir nedenden dolayı 'panik() 'olması durumunda bir blokta gerçekleştirilen herhangi bir SQL komutunu ROLLBACK'a ihtiyacım vardı. Bence bu klasik * try..catch..clean ve rethrow * stratejisidir.Çünkü bazı işlevler hakkında bir garanti yoktur * asla panik yapmayın * İçinde ... Daha iyi bir fikir mi? – Eonil

+0

Lütfen sorunuzu bu bilgilerle güncelleyin ve neden nil panik yaşadığınızı açıklayın. – nemo