介绍go中的泛型, 错误处理和自定义错误类型
Generics 从 1.18 版开始,Go 增加了对泛型(也称为类型参数)的支持。
generics.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 package mainimport "fmt" func MapKeys [K comparable , V any ](m map [K]V) []K { r := make ([]K, 0 , len (m)) for k := range m { r = append (r, k) } return r } type List[T any] struct { head, tail *element[T] } type element[T any] struct { next *element[T] val T } func (lst *List[T]) Push(v T) { if lst.tail == nil { lst.head = &element[T]{val: v} lst.tail = lst.head } else { lst.tail.next = &element[T]{val: v} lst.tail = lst.tail.next } } func (lst *List[T]) GetAll() []T { var elems []T for e := lst.head; e != nil ; e = e.next { elems = append (elems, e.val) } return elems } func main () { var m = map [int ]string {1 : "2" , 2 : "4" , 4 : "8" } fmt.Println("keys:" , MapKeys(m)) _ = MapKeys[int , string ](m) lst := List[int ]{} lst.Push(10 ) lst.Push(13 ) lst.Push(23 ) fmt.Println("list:" , lst.GetAll()) }
log 1 2 3 $ go run generics.go keys: [4 1 2] list: [10 13 23]
注意:Go 中没有定义 map keys 的迭代顺序,因此不同的调用可能会产生不同的顺序。
Errors 在 Go 中,通过显式、单独的返回值来传达错误是习以为常的。这与 Java 和 Ruby 等语言中使用的异常,以及 C 语言中有时使用的重载单一结果/错误值形成了鲜明对比。Go 的方法使得查看哪些函数返回错误变得容易,并能使用与其他非错误任务相同的语言结构来处理它们。
更多详情,请参阅 errors 包的文档 和本篇博文 。
errors.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 package mainimport ( "errors" "fmt" ) func f (arg int ) (int , error ) { if arg == 42 { return -1 , errors.New("can't work with 42" ) } return arg + 3 , nil } var ErrOutOfTea = fmt.Errorf("no more tea available" )var ErrPower = fmt.Errorf("can't boil water" )func makeTea (arg int ) error { if arg == 2 { return ErrOutOfTea } else if arg == 4 { return fmt.Errorf("making tea: %w" , ErrPower) } return nil } func main () { for _, i := range []int {7 , 42 } { if r, e := f(i); e != nil { fmt.Println("f failed:" , e) } else { fmt.Println("f worked:" , r) } } for i := range 5 { if err := makeTea(i); err != nil { if errors.Is(err, ErrOutOfTea) { fmt.Println("We should buy new tea!" ) } else if errors.Is(err, ErrPower) { fmt.Println("Now it is dark." ) } else { fmt.Printf("unknown error: %s\n" , err) } continue } fmt.Println("Tea is ready!" ) } }
log 1 2 3 4 5 6 7 8 $ go run errors.go f worked: 10 f failed: can't work with 42 Tea is ready! Tea is ready! We should buy new tea! Tea is ready! Now it is dark.
Custom Errors 通过在自定义类型上实现 Error() 方法,可以将其用作错误。下面是上面示例的一个变体,它使用自定义类型明确表示参数错误。
custom-errors.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package mainimport ( "errors" "fmt" ) type argError struct { arg int message string } func (e *argError) Error() string { return fmt.Sprintf("%d - %s" , e.arg, e.message) } func f (arg int ) (int , error ) { if arg == 42 { return -1 , &argError{arg, "can't work with it" } } return arg + 3 , nil } func main () { _, err := f(42 ) var ae *argError if errors.As(err, &ae) { fmt.Println(ae.arg) fmt.Println(ae.message) } else { fmt.Println("err doesn't match argError" ) } }
log 1 2 3 $ go run custom-errors.go 42 can't work with it
参考链接