Fehlerbehandlung in Go 2

Titel


Noch vor ein paar Tagen endete in Denver die nĂ€chste, bereits fĂŒnfte Konferenz in Folge, die grĂ¶ĂŸte Konferenz auf Go - GopherCon . Daraufhin gab das Go-Team eine wichtige ErklĂ€rung ab - EntwĂŒrfe des vorlĂ€ufigen Entwurfs der neuen Fehlerbehandlung und Generika in Go 2 werden veröffentlicht , und jeder ist zur Diskussion eingeladen.


Ich werde versuchen, das Wesentliche dieser EntwĂŒrfe in drei Artikeln im Detail zu wiederholen.


Wie viele wahrscheinlich wissen, gab das Go-Team im vergangenen Jahr (auch auf der GopherCon) bekannt, dass es Berichte ( Erfahrungsberichte ) und VorschlĂ€ge zur Lösung der Hauptprobleme von Go sammelt - die Punkte, die von Umfragen am meisten kritisiert wurden. Im Laufe des Jahres wurden alle VorschlĂ€ge und Berichte untersucht und geprĂŒft und halfen bei der Erstellung von EntwurfsentwĂŒrfen, die erörtert werden.


Beginnen wir also mit den EntwĂŒrfen des neuen Fehlerbehandlungsmechanismus .


Zu Beginn ein kleiner Exkurs:


  1. Go 2 ist ein bedingter Name - alle Innovationen werden Teil des normalen Prozesses der Veröffentlichung von Go-Versionen sein. Es ist also noch nicht bekannt, ob es Go 1.34 oder Go2 sein wird. Python 2/3 Skript wird nicht Eisen sein.
  2. EntwĂŒrfe von Designs sind nicht einmal VorschlĂ€ge , mit denen Änderungen in der Bibliothek, der Optimierung oder der Go-Sprache beginnen. Dies ist der Ausgangspunkt fĂŒr die vom Go-Team vorgeschlagene Designdiskussion nach mehrjĂ€hriger Arbeit an diesen Themen. Alles, was in den EntwĂŒrfen mit hoher Wahrscheinlichkeit beschrieben wird, wird sich Ă€ndern und im besten Fall erst nach wenigen Veröffentlichungen (ich gebe ~ 2 Jahre) RealitĂ€t.

Was ist das Problem bei der Fehlerbehandlung in Go?


Go entschied sich zunĂ€chst fĂŒr die Verwendung der "expliziten" FehlerprĂŒfung im Gegensatz zur "impliziten" PrĂŒfung, die in anderen Sprachen beliebt ist - Ausnahmen. Das Problem bei der impliziten FehlerprĂŒfung besteht darin, wie sie im Artikel „Sauberer, eleganter und nicht korrekter“ ausfĂŒhrlich beschrieben wird. Es ist sehr schwierig, visuell zu verstehen, ob sich das Programm bei bestimmten Fehlern korrekt verhĂ€lt.


Nehmen Sie ein Beispiel fĂŒr ein hypothetisches Go mit Ausnahmen:


func CopyFile(src, dst string) throws error {
    r := os.Open(src)
    defer r.Close()

    w := os.Create(dst)
    io.Copy(w, r)
    w.Close()
}

, . : io.Copy w.Close , .


, Go :


func CopyFile(src, dst string) error {
    r, err := os.Open(src)
    if err != nil {
        return err
    }
    defer r.Close()

    w, err := os.Create(dst)
    if err != nil {
        return err
    }
    defer w.Close()

    if _, err := io.Copy(w, r); err != nil {
        return err
    }
    if err := w.Close(); err != nil {
        return err
    }
}

, , , –  . , , – " ", - , , , .


, ( , , ..) , .


, Go . :


func CopyFile(src, dst string) error {
    r, err := os.Open(src)
    if err != nil {
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }
    defer r.Close()

    w, err := os.Create(dst)
    if err != nil {
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }

    if _, err := io.Copy(w, r); err != nil {
        w.Close()
        os.Remove(dst)
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }

    if err := w.Close(); err != nil {
        os.Remove(dst)
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }
}

, .



Go Go 2:


  • , ,
  • , ,
  • –  ,
  • Go ,

Go.



.


  • check(x,y,z) check err
  • handle – ,

check , handle ( handler, , . , return)


:


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

    r := check os.Open(src)
    defer r.Close()

    w := check os.Create(dst)
    handle err {
        w.Close()
        os.Remove(dst) // (  check )
    }

    check io.Copy(w, r)
    check w.Close()
    return nil
}

, ( main). :


func main() {
    hex, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
        log.Fatal(err)
    }

    data, err := parseHexdump(string(hex))
    if err != nil {
        log.Fatal(err)
    }

    os.Stdout.Write(data)
}

:


func main() {
    handle err {
        log.Fatal(err)
    }

    hex := check ioutil.ReadAll(os.Stdin)
    data := check parseHexdump(string(hex))
    os.Stdout.Write(data)
}

, . :


func printSum(a, b string) error {
    x, err := strconv.Atoi(a)
    if err != nil {
        return err
    }
    y, err := strconv.Atoi(b)
    if err != nil {
        return err
    }
    fmt.Println("result:", x + y)
    return nil
}

:


func printSum(a, b string) error {
    handle err { return err }
    x := check strconv.Atoi(a)
    y := check strconv.Atoi(b)
    fmt.Println("result:", x + y)
    return nil
}

:


func printSum(a, b string) error {
    handle err { return err }
    fmt.Println("result:", check strconv.Atoi(x) + check strconv.Atoi(y))
    return nil
}

check handle.


Check


check ( ) , "" error, , . nil, check (handler), return .


:


v1, ..., vN := check <>

:


v1, ..., vN, vErr := <>
if vErr != nil {
    <error result> = handlerChain(vn)
    return
}

vErr error <error result> , .


,


foo(check <>)

:


v1, ..., vN, vErr := <>
if vErr != nil {
    <error result> = handlerChain(vn)
    return
}
foo(v1, ..., vN)

Check try


try check – /, , , Rust Swift try ( Rust ? ).


try :


data := try parseHexdump(string(hex))

:


data, err := parseHexdump(string(hex))
if err == ErrBadHex {
    ... special handling ...
}
try err

, try c . check/handle , check .


Handle


handle , "" (handler), , check. (return) . ( , return) ( func foo() (bar int, err error)).


, " " – , , , error , , . :


func handler(err error) error {...}

( , , –  ).



–  , . (check) , , . , , –  . :


func process(user string, files chan string) (n int, err error) {
    handle err { return 0, fmt.Errorf("process: %v", err)  }      // handler A
    for i := 0; i < 3; i++ {
        handle err { err = fmt.Errorf("attempt %d: %v", i, err) } // handler B
        handle err { err = moreWrapping(err) }                    // handler C

        check do(something())  // check 1: handler chain C, B, A
    }
    check do(somethingElse())  // check 2: handler chain A
}

check 1 C, B A – . check 2 A, C B for-.


, . if , (handle) ( ) , – , , :


type Error struct {
    Func string
    User string
    Path string
    Err  error
}

func (e *Error) Error() string

func ProcessFiles(user string, files chan string) error {
    e := Error{ Func: "ProcessFile", User: user}
    handle err { e.Err = err; return &e } // handler A
    u := check OpenUserInfo(user)         // check 1
    defer u.Close()
    for file := range files {
        handle err { e.Path = file }       // handler B
        check process(check os.Open(file)) // check 2
    }
    ...
}

, handle defer, , , . – , . , handler B –  defer , . Go defer/panic handle/check , , -.


– (.. return), - . .


(panic) , .


-


– (handle err {}). " -" (default handler). handle , , -, , check ( ; — zero values).


-:


func printSum(a, b string) error {
    x := check strconv.Atoi(a)
    y := check strconv.Atoi(b)
    fmt.Println("result:", x + y)
    return nil
}


Go , . - , , . , t.Helper() , :


func TestFoo(t *testing.T) {
    handle err {
        t.Helper()
        t.Fatal(err)
    }
    for _, tc := range testCases {
        x := check Foo(tc.a)
        y := check Foo(tc.b)
        if x != y {
            t.Errorf("Foo(%v) != Foo(%v)", tc.a, tc.b)
        }
    }
}

(shadowing)


check (:=), err. handle/check .



defer/panic


(defer/panic handle/check) . .


handle defer (, , , ), handle/check defer-. :


func Greet(w io.WriteCloser) error {
    defer func() {
        check w.Close()
    }()
    fmt.Fprintf(w, "hello, world\n")
    return nil
}

, .



Go –  , . - "", , defer, break goto. , goto, , .



try, catch, ? , . , Go , check handle .


, handle catch , ( , (keywords) ).



Go2?


. Go, 2-3 , – . , 2-3 .


, , Go2 –  . , Go – Go 1.20 . .


, ?


. / . , , , Go.


Go 2 – , if err != nil {} , handle/check?


, , if err , –  , . , .


?  , Go .


. , .


?


, , . , - . , , , , .


, ! ?


- Go2ErrorHandlingFeedback



  • Go —  handle/check
  • -
  • , ,
  • / ( defer/panic)



? ?


Source: https://habr.com/ru/post/de422049/


All Articles