【问题标题】:Generic Functions in GoGo 中的泛型函数
【发布时间】:2017-03-10 20:15:29
【问题描述】:

我正在学习Go,文档和互动课程说空的interface 可以容纳任何类型,因为它不需要额外实现的方法。

举个例子:

func describe(i interface{}) {
    fmt.Printf("Type: %T | Value: %v\n", i, i)
}

...会打印出来...

"Type: int | Value: 5" // for i := 5
"Type: string | Value: test" // for i := "test"
... etc

所以我想我的问题是这是Go's 实现泛型函数的方式,还是有另一种更合适的方式来实现它们。

【问题讨论】:

  • Go 没有真正的泛型,所以这是一种解决方法。但是,当您必须执行类型断言以从复合类型中提取数据或强制执行其他规则时,该系统就会崩溃。
  • @squiguy 所以为了实现一个准泛型,你本质上是使用带有类型开关的空接口?
  • 很难说这是 100% 正确的,但这是一种方式。除非你绝对想这样做,否则我会尽量避免。
  • 请参阅@mayank 的answer below。现在有一个关于 Go 中的泛型的提案草案

标签: generics go interface


【解决方案1】:

截至 2021 年 6 月,泛型无法用于生产,但对于即将推出的 go 泛型功能感兴趣的人,使用 go 的 accepted design proposal(预计 2022 年初可用),您可以编写一个泛型函数 @ 987654323@如下

package main

import (
    "fmt"
)

// T can be any type. Compilation will fail if T is not iterable.
func Print[T any](s []T) {
    for _, v := range s {
        fmt.Print(v)
    }
}

func main() {
    // Passing list of string works
    Print([]string{"Hello, ", "world\n"})

    // You can pass a list of int to the same function as well
    Print([]int{1, 2})
}

输出:

Hello, world
12

【讨论】:

【解决方案2】:

Go 范式通常是通过在非空接口中实现行为来避免这种情况。例如,假设您想打印具有特定类型格式的内容:

func Print(i interface{}) {
    switch o := i.(type) {
        case int64:
            fmt.Printf("%5d\n", o)
        case float64:
            fmt.Printf("%7.3f\n", o)
        case string:
            fmt.Printf("%s\n", o)
        default: // covers structs and such
            fmt.Printf("%+v\n", o)
    }
}

或者,您可以为知道如何将自己串起来的事物定义一个接口(这在基础库中以fmt.Stringer 的形式存在),并使用它:

type Stringer interface {
    String() string
}

func Print(o Stringer) {
    fmt.Println(o.String())
}

type Foo struct {
    a, b int
}

func (f Foo) String() string {
    // Let's use a custom output format that differs from %+v
    return fmt.Sprintf("%d(%d)", f.a, f.b) 
}

type Bar struct {
    t bool
}

func (b Bar) String() string {
    if b.t {
        return "TRUE! =D"
    }
    return "false =("
}

https://play.golang.org/p/Ez6Hez6cAv

这让您拥有类似泛型的功能,但仍保持类型安全,并且行为本身由类型定义,而不是您的泛型函数。

Go 鼓励你以这种方式思考类型,基于它们的行为,它们可以做什么而不是它们包含

【讨论】:

    【解决方案3】:

    Golang 没有泛型类型,因此解决此问题的方法是传递 interface 类型并在函数中使用类型开关。

    【讨论】:

    • 不需要类型开关......请参阅@Kaedys 回答的第二部分
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多