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

Lepaskan: 2023-08-04 17:05:37
ke hadapan
1273 orang telah melayarinya


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 {
    ...
}
Salin selepas log masuk

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
Salin selepas log masuk

Kod yang dijana oleh pengkompil:

if err != nil {
    return handler(err)
}
Salin selepas log masuk

Dalam fungsi, ia boleh menjadi seperti berikut:

func(args...) (rtype1, rtypes..., rtypeN, error) {
    try err, handler
    ...
}
Salin selepas log masuk

Kod yang dihasilkan selepas terjemahan:

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

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

try err
Salin selepas log masuk

Kod yang diterjemahkan:
if err != nil {
    return err
}
Salin selepas log masuk
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)
Salin selepas log masuk

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)
    }
    ...
}
Salin selepas log masuk

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 }
    }
}
Salin selepas log masuk

另外在日常的 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
}
Salin selepas log masuk

引入 try-hanlder 后,能够做到:

  • 插入错误的返回语句,进行机制预设。
  • 在返回错误之前将错误处理函数组合在一起,便于后续的处理。

总结

在这个新提案中,一旦实施,就可以减少如下代码的编写:

if err != nil {
  return ...
}
Salin selepas log masuk

在代码编写上会节省一些行数,且可以为错误处理机制引入一些新的 ”操作“,这是该提案的优势。

但是从 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!

Label berkaitan:
go
sumber:Golang菜鸟
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan