【问题标题】:How to create a variable with needed type instead of type assertion如何创建具有所需类型而不是类型断言的变量
【发布时间】:2021-03-19 14:05:23
【问题描述】:

我有一个带有接口的函数,如下所示:

func method(data interface{})

.. 因为我需要处理具有共同字段/方法的不同结构。在这个函数中,我在不同的地方使用了数十次或数百次data。一直加switch a.(type) { case .. case ..真的很不爽。

有没有一种方法可以创建一个只有一个具有所需类型的switch 的变量,然后以后在任何地方都使用这个变量?比如:

var a .... // something here

switch data.(type) {
case *Struct1:
    a = data.(*Struct1)
case *Struct2:
    a = data.(*Struct2)
}

// Continue with 'a' only
a.Param = 15
fmt.Println(a.String())

【问题讨论】:

    标签: go


    【解决方案1】:

    Go 是一种静态类型语言,a 的类型必须在编译时知道。而且由于 Go 还不支持泛型,所以你无法为所欲为。

    尝试提出其他解决方案,例如将您想用a 做的事情抽象到一个接口中,并让具体类型实现该接口。那么a可以是这个接口类型的变量,你可以调用它的方法。

    如果你能做到这一点,其实你甚至可以把data类型的参数改成这个接口,不需要类型断言和类型切换。

    或者,您可以使用反射来访问由其名称标识的公共字段(用于获取或设置),但反射不提供编译时保证,而且通常效率较低。有关如何执行此操作的示例,请参阅此问题:Assert interface to its type

    【讨论】:

    • struct 的字段呢?通用接口不是没有字段吗?
    • @Alexey 接口只能定义方法,不能定义结构字段。为此,您需要添加 setter(和/或 getter)方法。您可以使用嵌入来减少代码的重复性。
    【解决方案2】:

    你不能直接做你在问题中要求的事情,go 是静态类型的,所以你不能拥有一个可以保存不同类型的变量,并且仍然像类型化一样访问该变量。

    如果您只处理方法中的公共结构字段,则最好将所有公共变量收集在其自己的结构中,如下所示 commons 结构并让您的 method 采用该类型作为论据

    package main
    
    import (
        "fmt"
    )
    
    type commons struct {
        name string
        age int
    }
    type structA struct {
        commons
        other_stuff int
    }
    
    type structB struct {
        commons
        foo string
    }
    
    func method(c* commons) {
        fmt.Println(c)
        c.age +=1
    
    }
    func main() {
        a := structA{commons{"foo", 44}, 1} 
        b := structB{commons{"bar", 33}, "test"} 
        method(&a.commons)
        method(&b.commons)
        fmt.Println(a)
    }
    

    Go playground

    【讨论】:

      【解决方案3】:

      我无法弄清楚你的真正目标是什么,但如果你想编写的“方法”处理来自相似结构的公共字段,并且你无法使用 Type Embedding 修复原始结构,如 @没有上面说的,那么你可以尝试制作另一个结构供方法内部使用:

      var v Vehicle // with common fields
      
      switch data.(type) {
      case *Car:
          v.Handle = data.(*Car).Handle // or CircleHandle
      case *Motorcycle:
          v.Handle = data.(*Motorcycle).Handle // or BarHandle
      }
      
      v.Degree = 15
      v.Speed = 50
      v.Direction = "left"
      v.Style = "rough"
      /// so many things on `v`...
      
      steering(v)
      

      我认为这不是一个好方法,但有时... :-)

      【讨论】:

        猜你喜欢
        • 2022-01-22
        • 2012-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-30
        • 2021-02-23
        • 1970-01-01
        • 2021-11-21
        相关资源
        最近更新 更多