美文网首页
Go 泛型初体验

Go 泛型初体验

作者: rayjun | 来源:发表于2021-08-28 19:26 被阅读0次

    在 Go1.17 中,千呼万唤的泛型终于出来了,但又没有完全出来。在 Go1.17 的发布文档中,并没有提到泛型,但是眼见的网友发现,泛型相关的代码其实已经合并了,只是没有默认启用。目前来说,泛型的玩玩就行,不要用到生产中。

    泛型有望在 Go1.18 版本中发布。

    1. 启用泛型

    泛型的功能虽然添加到 Go.1.17 中了,如果要使用,需要添加一些参数开启,首先需要安装 Go1.17:

    $ go version                                                                                                                                                                                                                                                                       ~
    go version go1.17 darwin/amd64
    

    然后可以在编译 的参数中看到泛型的影子,下面的 -G 参数就是启用泛型所需要的参数:

    $ go tool compile -h                                                                                                                                                                                                                                                               ~
    usage: compile [options] file.go...
      -% int
            debug non-static initializers
      -+    compiling runtime
      -B    disable bounds checking
      -C    disable printing of columns in error messages
      -D path
            set relative path for local imports
      -E    debug symbol export
      -G    accept generic code
    

    看一个例子:

    package main
    
    import (
        "fmt"
    )
    
    type Addable interface {
        type int, int8, int16, int32, int64,
            uint, uint8, uint16, uint32, uint64, uintptr,
            float32, float64, complex64, complex128,
            string
    }
    
    func add[T Addable](a, b T) T {
        return a + b
    }
    
    func main() {
        fmt.Println(add(1,2))
    
        fmt.Println(add("foo","bar"))
    }
    

    如果直接运行上面的代码,会报下面的错误,这也说明 Go1.17 默认是不支持泛型的:

    $ go run main.go                                                                                                                                                                                                                       
    # command-line-arguments
    ./main.go:8:2: syntax error: unexpected type, expecting method or interface name
    ./main.go:14:6: missing function body
    ./main.go:14:9: syntax error: unexpected [, expecting (
    

    需要加上下面的参数:

    $ go run -gcflags=-G=3 main.go                                                                                                                                                                                                     ↵
    3
    foobar
    

    第一个泛型程序成功运行了。

    2. 类型参数和约束

    在 Go 泛型中,增加了两个新概念,一个是 type parameters,下面代码中的 T 就是类型参数,用来表示泛型:

    func add[T Addable](a, b T) T {
        return a + b
    }
    

    可以说 type parameters 在 Go 中就是泛型的意思。

    再看一下下面这段代码,这里泛型的类型是 any,上面的代码则是自定义的 Addable。

    func print[T any](a T) {
         fmt.Printf("%v", a)
    }
    

    上面的 add 函数是有约束的,只能使用 Addable 中定义的类型,如果我们把 Addable 中的 string 去掉,代码就会报下面的错误:

    $ go run -gcflags=-G=3 main.go
    # command-line-arguments
    ./main.go:24:20: string does not satisfy Addable (string not found in int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128)
    

    而 print 函数则可以接受任何类型的参数。

    这就是 Go 中泛型最重要的两个概念:类型参数约束

    3. 类型推断

    正常使用泛型的时候,其实要使用下面这种方式来调用的,以 add 方法为例:

    add[int](1,2)
    add[string]("foo","bar")
    

    但是按照下面的方式写代码也是合法的:

    add(1,2)
    add("foo","bar")
    

    可以把泛型参数省略调,这不部分的工作其实是 Go 编译器来完成的,编译器会根据传入的实际类型来推断,而不用每次写代码的时候都指明泛型的类型。

    类型推断可以让代码简洁不少。

    4. 小结

    Go 泛型涉及到的内容大致就是上面这些了,当然泛型也可以写出很复杂的代码,但实际上涉及到的内容也就是上面那些。总体来说还是比较简洁的,这也与 Go 的设计理念符合。

    Go 泛型目前还没有正式发布,上面的内容在正式发布的时候可能也会有所调整,所以不要在生产中区使用泛型。

    本文例子来源于:https://github.com/mattn/go-generics-example

    文 / Rayjun

    相关文章

      网友评论

          本文标题:Go 泛型初体验

          本文链接:https://www.haomeiwen.com/subject/qbfiiltx.html