【问题标题】:Does go support multi-types? (type of generics)go 支持多类型吗? (泛型类型)
【发布时间】:2020-07-09 18:15:30
【问题描述】:
type MyNumber interface {
    float32, float64, uint, int // this is not supported
}

func PrintNumber(n MyNumber) {
    switch n.(type) {
    case float32, float64, uint, int:
        fmt.Printf("%v\n", n)
    default:
        panic("PrintNumber only supports types float32, float64, uint, int")
    }
}

在go中,可以定义一个空白接口,基本上允许任何类型

var v interface{}
v = "string"
v = 0.1

有没有办法将允许的类型减少到特定的类型列表?

类似

type MyNumber float32, float64, uint, int

type MyNumber interface {
    float32, float64, uint, int
}

这样我可以让编译器检查函数是否支持该类型。

【问题讨论】:

    标签: go types interface


    【解决方案1】:

    有没有办法将允许的类型减少到 [空接口] 的特定类型列表?

    在编译时,没有。

    但是,您可以选择在运行时使用限制。当有其他选择时应该避免这种情况,因为它不能提供那么多的安全性。

    这是在标准库中的许多地方完成的,例如 json marshaler,它需要一个指针作为目标。

    【讨论】:

      【解决方案2】:

      您不能在编译时以您希望的方式强制使用一组具体类型。

      您可以做的是使用接口。列出您期望从实现中获得的接口中的方法。那么具体的运行时类型是什么就无关紧要了。您仅通过接口与值交互,这在编译时保证它由传递的值实现。

      例如如果您希望该值提供 int32 值,请使用此接口:

      type HasInt32 interface {
          Int32() int32
      }
      
      func f(i HasInt32) {
          fmt.Println("int32 value:", i.Int32())
      }
      

      传递的值是否具有int32float64 作为其基础类型,或者它是任何其他复杂类型都没有关系。你需要一个int32,这就是你得到的。实现者负责如何产生该值。

      例如:

      type MyInt32 int32
      
      func (m MyInt32) Int32() int32 { return int32(m) }
      
      type MyStruct struct {
          i int64
      }
      
      func (m MyStruct) Int32() int32 { return int32(m.i) }
      

      测试它:

      var m MyInt32 = 1
      f(m)
      
      var s MyStruct = MyStruct{i: 2}
      f(s)
      

      哪些输出(在Go Playground 上试试):

      int32 value: 1
      int32 value: 2
      

      【讨论】:

      • 这种方法将允许我使用 ToInt 和 ToString 方法创建一个接口,但是将该接口传递给一个方法将需要传递的结构来实现两者:“ToInt 和 ToString”,但是我需要的是“ToInt 或 ToString”
      【解决方案3】:

      有没有办法将允许的类型减少到特定的类型列表?

      是的,从 Go 1.18 开始,使用带有类型元素的接口。但此类接口只能用作类型参数的约束。在规范的草案版本中,Interface types 下提到了这一点:

      包含非接口类型、~T 形式的术语或联合的接口只能用作类型约束,或用作用作约束的其他接口的元素。它们不能是值或变量的类型,也不能是其他非接口类型的组件。

      简而言之,在接口中,除了方法签名和其他嵌入式接口之外,您现在还可以添加 type 元素。这定义了一个类型约束,即“相应类型参数的允许类型参数集”。

      特别是:

      • 接口约束可以指定一个或多个类型元素。它将类型参数限制为指定的类型。您可以将多个类型元素指定为 union(更多信息:Go Generics - Unions
      type MyNumber interface {
          float32 | float64 | uint | int
      }
      
      type MyNumber interface {
          ~float32 | ~float64 | ~uint | ~int
      }
      
      • 您仍然可以在这样的接口中指定方法签名。它将类型参数限制为那些也实现了接口的类型集:
      // set of types with underlying int that also implement `String() string`
      type MyNumber interface {
          ~int
          String() string
      }
      
      • 作为上述推论,如果接口指定了非近似的预声明类型方法,则没有类型会满足该接口(因为您不能在预声明类型上声明方法)
      // empty type set
      type MyNumber interface {
          int
          String() string
      }
      

      如前所述,您仅将其用作类型参数约束,您将无法在类型切换、声明变量等中使用它:

      func foo[T MyNumber](v T) {
          // ...
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-07-15
        • 1970-01-01
        • 2016-02-22
        • 2019-07-21
        • 1970-01-01
        • 1970-01-01
        • 2014-02-26
        相关资源
        最近更新 更多