Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Cubalah Adakah cadangan baharu itu boleh dipercayai? Ingin memudahkan pengendalian ralat

Cubalah Adakah cadangan baharu itu boleh dipercayai? Ingin memudahkan pengendalian ralat

Golang菜鸟
Golang菜鸟ke hadapan
2023-08-04 17:05:371254semak imbas


Baru-baru ini, cadangan percubaan baharu "cadangan: Pergi 2: pengendalian ralat: kenyataan cuba dengan pengendali[1]" telah mencetuskan perbincangan hangat dalam komuniti, mari kita lawan masyarakat semula! ! !

Hari ini Jianyu akan membukanya dengan semua orang dan melihat sama ada ini boleh membuka dan menyusun semula mekanisme pengendalian ralat Go. .

Dengan keluaran generik Go1.18, generik asal yang paling bercanggah telah menerima penyelesaian awal. Menurut tinjauan komuniti, cabaran terbesar yang dihadapi oleh pembangun apabila menggunakan Go telah beralih kepada pengendalian ralat dan tenaga perlu dilaburkan untuk "menyelesaikan"nya.

Faktor lain ialah diketahui umum bahawa kod pengendalian ralat Go agak menyusahkan Jurutera sering bergurau bahawa 30% daripada projek Go mempunyai jika err = nil. Kod berikut:

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

Semoga ia lebih elegan. Ramai rakan juga bersetuju dengan reka bentuk ini, ia sememangnya satu pemprosesan yang mudah dan intuitif, yang telah membentuk perjuangan dalam masyarakat. .
Cubalah Adakah cadangan baharu itu boleh dipercayai? Ingin memudahkan pengendalian ralatKod berikut:
try err, handler

Kod yang dijana oleh pengkompil:

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

Dalam fungsi, ia boleh menjadi seperti berikut:

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

Kod yang dihasilkan selepas terjemahan:

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

Ia juga boleh diproses jika != tiada. Kod berikut:

try err

Kod yang diterjemahkan:
if err != nil {
    return err
}
tidak akan memanggil pengendali yang tidak wujud untuk diproses, dan akan kembali terus. Tiga baris (jika err != logik nil) terus menukar 3 perkataan (cuba).

Jika anda tidak mahu menulis fungsi, anda juga boleh terus:

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

Senario penangguhan+cuba boleh seperti berikut:

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

Parameter input lebih fleksibel, penulis berharap ia adalah generik bahawa ia boleh menyesuaikan diri dengan keperluan pelbagai senario.

示例和实践

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

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

Atas ialah kandungan terperinci Cubalah Adakah cadangan baharu itu boleh dipercayai? Ingin memudahkan pengendalian ralat. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:Golang菜鸟. Jika ada pelanggaran, sila hubungi admin@php.cn Padam