Récemment, la nouvelle proposition d'essai "proposition : Go 2 : gestion des erreurs : instruction try avec gestionnaire[1]" a déclenché des discussions animées dans la communauté, combattons à nouveau la communauté ! ! !
Aujourd'hui, Jianyu va l'ouvrir avec tout le monde et voir si cela peut ouvrir et réorganiser le mécanisme de gestion des erreurs Go.
L'auteur de la proposition @Greg Weber de PingCAP le fera sur la base de deux facteurs. L'un est clairement mentionné dans "Go Developer Survey 2022 Q2 Results[2]".
Avec la sortie des génériques Go1.18, les génériques originaux les plus contradictoires ont reçu une solution préliminaire. Selon des enquêtes communautaires, le plus grand défi auquel sont confrontés les développeurs lors de l'utilisation de Go est désormais la gestion des erreurs, et de l'énergie doit être investie pour le « résoudre ».
Un autre facteur est qu'il est bien connu que le code de gestion des erreurs Go est relativement lourd. Les ingénieurs plaisantent souvent en disant que 30 % d'un projet Go a if err = nil.
Le code suivant :
_, err := f() if err != nil { ... } _, err = r() if err != nil { ... } _, err = w() if err != nil { ... }
J'espère le rendre plus élégant. De nombreux amis sont également d'accord avec cette conception. Il s'agit en effet d'un traitement simple et intuitif, qui a suscité un débat dans la communauté.
La solution mentionnée dans cette proposition est d'ajouter une nouvelle instruction try pour obtenir une gestion concise des erreurs et rendre le traitement de if err != nil fluide.
Le code suivant :
try err, handler
Le code généré par le compilateur :
if err != nil { return handler(err) }
Dans la fonction, il peut être comme suit :
func(args...) (rtype1, rtypes..., rtypeN, error) { try err, handler ... }
Le code généré après traduction :
func(args...) (rtype1, rtypes..., rtypeN, error) { if err != nil { return Zero(rtype1), Zeros(rtypes...)..., Zero(rtypeN), handler(err) } ... }
Il ne peut également être traité que si erreur != nul. Le code suivant :
try err
Le code traduit :
if err != nil { return err }
n'appellera pas le gestionnaire inexistant pour le traitement et reviendra directement. Trois lignes (si err != logique nulle) changent directement 3 mots (essayez).
Si vous ne souhaitez pas écrire de fonction, vous pouvez aussi directement :
x, err := f() try err, fmt.Errorf("f fail: %w", err)
Le scénario defer+try peut être le suivant :
func CopyFile(src, dst string) error { defer try func(err error) error { return fmt.Errorf("copy %s %s: %w", src, dst, err) } ... }
Les paramètres d'entrée sont plus flexibles. L'auteur espère que c'est générique, donc. qu'il peut s'adapter aux exigences de divers scénarios.
针对本提案,原作者给出了各类使用场景的示例。如下代码:
import ( "fmt" ) // This helper should be defined in the fmt package func Handlew(format string, args ...any) func(error) error { return func(err error) error { args = append(args, err) return fmt.Errorf(format+": %w", args...) } } // This helper should be defined in the fmt package func Handlef(format string, args ...any) func(error) error { return func(err error) error { args = append(args, err) return fmt.Errorf(format+": %v", args...) } } func valAndError() (int, error) { return 1, fmt.Errorf("make error") } func newGo() (int, error) { x, err := valAndError() try err // Common formatting functions will already be provided i := 2 x, err = valAndError() try err, Handlew("custom Error %d", i) // Using a custom error type // For convenience the error type can expose a method to set the error x, err = valAndError() try err, TheErrorAsHandler(i) } type TheError struct{ num int err error } func (t TheError) Error() String { return fmt.Sprintf("theError %d %v", t.num, t.err) } func TheErrorAsHandler(num int) func(err) TheError { return func(err error) TheError { return theError{ num: i, err: err } } }
另外在日常的 Go 工程中,提案作者认为 CopyFile 函数是新提案语句的一种很好的实践。为此基于 try-handler 进行了一版改造和说明。
如下代码:
// This helper can be used with defer func handle(err *error, handler func(err error) error) { if err == nil { return nil } *err = handler(err) } func CopyFile(src, dst string) (err error) { defer handle(&err, func(err error) error { return fmt.Errorf("copy %s %s: %w", src, dst, err) }) r, err := os.Open(src) try err defer r.Close() w, err := os.Create(dst) try err, func(err error) error { os.Remove(dst) // only if Create fails return fmt.Errorf("dir %s: %w", dst, err) } defer w.Close() err = io.Copy(w, r) try err err = w.Close() try err return nil }
引入 try-hanlder 后,能够做到:
在这个新提案中,一旦实施,就可以减少如下代码的编写:
if err != nil { return ... }
在代码编写上会节省一些行数,且可以为错误处理机制引入一些新的 ”操作“,这是该提案的优势。
但是从 Go 开发者的角度而言,会引入一些新的副作用,例如:初学者的学习成本、Go 工具链的改造、程序理解的复杂度增加。
另外新的语句,似乎比较难与 Go1.13 引入的 error.Is 和 As 有较好的相关联性。如果是做一个第三方用户库引入倒可以,但若是作为标准进入 Go 源代码中,似乎又有些格格不入(提案作者希望进入)。
看了那么多提案,Go 错误处理机制的 ”升级“,似乎陷入了手心手背都是肉的阶段...
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!