Penanganan Kesalahan saat Go 2

judul


Hanya beberapa hari yang lalu di Denver, yang berikutnya, sudah 5 berturut-turut, konferensi terbesar di Go- GopherCon berakhir . Pada saat itu, tim Go membuat pernyataan penting - draft desain awal penanganan kesalahan baru dan obat generik di Go 2 diterbitkan , dan semua orang diundang untuk berdiskusi.


Saya akan mencoba menceritakan kembali esensi dari draft ini dalam tiga artikel.


Seperti yang mungkin diketahui banyak orang, tahun lalu (juga di GopherCon), tim Go mengumumkan bahwa mereka mengumpulkan laporan ( laporan pengalaman ) dan saran untuk menyelesaikan masalah utama Go - poin-poin yang paling dikritik oleh jajak pendapat. Selama tahun ini, semua proposal dan laporan dipelajari dan dipertimbangkan, dan membantu dalam membuat rancangan desain, yang akan dibahas.


Jadi, mari kita mulai dengan konsep mekanisme penanganan kesalahan yang baru .


Untuk memulai, penyimpangan kecil:


  1. Go 2 adalah nama bersyarat - semua inovasi akan menjadi bagian dari proses normal melepaskan versi Go. Jadi masih belum diketahui apakah akan Go 1.34 atau Go2. Skrip Python 2/3 tidak akan menjadi besi.
  2. Rancangan desain bahkan bukan proposal , yang dengannya perubahan apa pun di perpustakaan, tuning, atau bahasa Go dimulai. Ini adalah titik awal untuk diskusi desain yang diusulkan oleh tim Go setelah beberapa tahun bekerja pada masalah ini. Segala sesuatu yang dijelaskan dalam draft dengan tingkat probabilitas tinggi akan diubah, dan, dalam skenario terbaik, akan menjadi kenyataan hanya setelah beberapa rilis (saya berikan ~ 2 tahun).

Apa masalah dengan penanganan kesalahan di Go?


Go awalnya membuat keputusan untuk menggunakan pemeriksaan kesalahan "eksplisit", sebagai lawan dari pemeriksaan "implisit" yang populer di bahasa lain - pengecualian. Masalah dengan pemeriksaan kesalahan implisit adalah bagaimana hal itu dijelaskan secara rinci dalam artikel "Bersih, lebih elegan dan tidak lebih benar" , yang sangat sulit untuk dipahami secara visual jika program berperilaku dengan benar jika terjadi kesalahan tertentu.


Ambil contoh Go hipotetis dengan pengecualian:


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/id422049/


All Articles