Heim  >  Artikel  >  Backend-Entwicklung  >  Probieren Sie es aus. Ist der neue Vorschlag zuverlässig? Sie möchten die Fehlerbehandlung vereinfachen

Probieren Sie es aus. Ist der neue Vorschlag zuverlässig? Sie möchten die Fehlerbehandlung vereinfachen

Golang菜鸟
Golang菜鸟nach vorne
2023-08-04 17:05:371257Durchsuche


Kürzlich hat der neue Try-Vorschlag „Vorschlag: Go 2: Fehlerbehandlung: Try-Anweisung mit Handler[1]“ hitzige Diskussionen in der Community ausgelöst, lasst uns die Community erneut bekämpfen! ! !

Heute wird Jianyu es mit allen öffnen und sehen, ob dadurch der Go-Fehlerbehandlungsmechanismus geöffnet und neu organisiert werden kann.

Hintergrund

Der Vorschlagsautor @Greg Weber von PingCAP wird dies auf der Grundlage von zwei Faktoren tun. Einer wird in „Go Developer Survey 2022 Q2 Results[2]“ deutlich erwähnt.

Probieren Sie es aus. Ist der neue Vorschlag zuverlässig? Sie möchten die Fehlerbehandlung vereinfachen

Mit der Veröffentlichung von Go1.18-Generika haben die ursprünglich widersprüchlichsten Generika eine vorläufige Lösung erhalten. Community-Umfragen zufolge liegt die größte Herausforderung für Entwickler bei der Verwendung von Go in der Fehlerbehandlung, und es muss Energie investiert werden, um das Problem zu „lösen“.

Ein weiterer Faktor ist, dass Go-Fehlerbehandlungscode bekanntermaßen relativ umständlich ist. Ingenieure scherzen oft, dass bei 30 % eines Go-Projekts „if err“ = Null ist.

Der folgende Code:

_, err := f()
if err != nil {
    ...
}
_, err = r()
if err != nil {
    ...
}
_, err = w()
if err != nil {
    ...
}

Ich hoffe, es eleganter zu machen. Viele Freunde stimmen diesem Design ebenfalls zu. Es handelt sich tatsächlich um eine einfache und intuitive Verarbeitung, die in der Community zu einem Kampf geführt hat.

Try-Handler-Vorschlag

Die in diesem Vorschlag erwähnte Lösung besteht darin, eine neue Anweisung try hinzuzufügen, um eine präzise Fehlerbehandlung zu erreichen und die Verarbeitung von if err != nil reibungslos zu gestalten.

Der folgende Code:

try err, handler

Der vom Compiler generierte Code:

if err != nil {
    return handler(err)
}

In der Funktion kann er wie folgt sein:

func(args...) (rtype1, rtypes..., rtypeN, error) {
    try err, handler
    ...
}

Der nach der Übersetzung generierte Code:

func(args...) (rtype1, rtypes..., rtypeN, error) {
    if err != nil {
            return Zero(rtype1), Zeros(rtypes...)..., Zero(rtypeN), handler(err)
    }
    ...
}

Es kann auch nur verarbeitet werden, wenn err != Null. Der folgende Code:

try err

Der übersetzte Code:

if err != nil {
    return err
}

ruft den nicht vorhandenen Handler nicht zur Verarbeitung auf und kehrt direkt zurück. Drei Zeilen (wenn err != Null-Logik) ändern direkt 3 Wörter (versuchen Sie es).

Wenn Sie keine Funktion schreiben möchten, können Sie auch direkt:

x, err := f()
try err, fmt.Errorf("f fail: %w", err)

Das Defer+Try-Szenario kann wie folgt aussehen:

func CopyFile(src, dst string) error {
    defer try func(err error) error {
        return fmt.Errorf("copy %s %s: %w", src, dst, err)
    }
    ...
}

Die Eingabeparameter sind flexibler, daher hofft der Autor dass es sich an die Anforderungen verschiedener Szenarien anpassen kann.

示例和实践

针对本提案,原作者给出了各类使用场景的示例。如下代码:

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 错误处理机制的 ”升级“,似乎陷入了手心手背都是肉的阶段...

Das obige ist der detaillierte Inhalt vonProbieren Sie es aus. Ist der neue Vorschlag zuverlässig? Sie möchten die Fehlerbehandlung vereinfachen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:Golang菜鸟. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen