Just a couple of days ago, the next, already the 5th Go conference, the largest Go conference, GopherCon, ended in Denver. On it, the Go team made an important statement - the drafts of the preliminary design of error handling and generics in Go 2 are published , and everyone is invited to discuss.
I will try to retell in detail the essence of these drafts in three articles.
As many of you know, for sure, last year (also at GopherCon), the Go team announced that it was collecting experience reports and suggestions for solving the main problems of Go β those moments that, according to surveys, collected the most criticism. During the year, all the offers and reports were studied and reviewed, and helped in the creation of draft designs, which will be discussed.
So let's start with the drafts of the new error handling mechanism .
For a start, a small digression:
In Go, it was originally decided to use "explicit" error checking, as opposed to the "implicit" checking popular in other languages ββ- exceptions. The problem with implicit error checking is how it is described in detail in the article βCleaner, more elegant and not more correctβ , that it is very difficult to visually understand whether the program behaves correctly in case of certain errors.
Take the example of a hypothetical Go with exceptions:
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.
.
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
( ) , "" 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)
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
, "" (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)
}
}
}
check
(:=
), err
. handle
/check
.
(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) ).
. Go, 2-3 , β . , 2-3 .
, , Go2 β . , Go β Go 1.20 . .
. / . , , , Go.
if err != nil {}
, handle
/check
?, , if err
, β , . , .
. , .
, , . , - . , , , , .
handle
/check
defer
/panic
)? ?
Source: https://habr.com/ru/post/422049/
All Articles