【问题标题】:How to initialize a array of interface in golang?如何在golang中初始化一个接口数组?
【发布时间】:2018-09-03 12:50:37
【问题描述】:

我想初始化一个包含界面列表的地图,而不必一一添加:

type Pixel struct {
    X float64
    Y float64
}

type Vertex struct {
    X float64
    Y float64
    Z float64
}
type testpair struct {
    filename       string
    values     []interface{}
}
var tests = map[string]testpair{
   "test1": {
               filename: "file1.csv",
               values:  []Pixel{
                           {X: 12.5, Y: 23.4},
                           {X: 17.2, Y: 7.9},
                      }
            },
   "test2": {
               filename: "file2.csv",
               values:  []Vertex{
                           {X: 10.7, Y: 13.3, Z: 25.1},
                           {X: 18.3, Y: 16.9, Z: 16.4},
                      }
            }, 
}

编译器会输出这样的错误:

不能在字段值中使用 []Pixel 字面量(类型 []Pixel)作为类型 []interface {}

如果我将 []interface{} 切换为 []Pixel,我可以初始化地图,但我只能使用唯一类型的 Pixel 或 Vertex。

有没有办法强制编译器接受具有特定结构的数组初始化,同时将其声明为接口数组?

【问题讨论】:

  • []Pixel{ {X:...}, {X:...}} 替换为:[]interface{}{ Pixel{X:...}, Pixel{X:...}}

标签: go


【解决方案1】:

如果您必须创建一个值切片来传递给需要 interface{} 切片(取决于上下文,可能是也可能不是适当的设计)或任何更具体接口的切片的东西,您必须完全指定每个元素,如下所示:

[]interface{}{ 
    Pixel{X: 12.5, Y: 23.4},
    Pixel{X: 17.2, Y: 7.9},
}

这也意味着您可以传递以下内容:

[]interface{}{
    Pixel{X: 12.5, Y: 23.4},
    Vertex{X: 10.7, Y: 13.3, Z: 25.1},
}

这几乎不是你想要的,编译器不会警告你。不过,我认为测试代码没什么大不了的。

【讨论】:

    【解决方案2】:

    有没有办法强制编译器接受具有特定结构的数组初始化,同时将其声明为接口数组?

    没有。基本上你不能强迫 Go 编译器做任何事情。

    另请参阅常见问题解答:https://golang.org/doc/faq#convert_slice_of_interface

    您必须提供[]interface{}

    但是请停止这样做,并想出一些不需要空界面的东西。

    【讨论】:

    • 只是好奇你为什么提到,“想出一些不需要空界面的东西”,有什么文章可以进一步阅读吗?
    • 我要做的是创建一个容器,其中包含从同一个父对象继承的对象实例,我在这里使用纯接口使事情易于理解,但它可以是我自己的自定义界面。
    • @AmineKerkeni 继承在 Go 中不是一个东西。
    • @AmineKerkeni 空界面不是“纯”界面,它是罐头和其他东西的蠕虫。如果您想收集两种不同的东西(像素和顶点),请查看您对它们共同执行的操作。将其提取到接口中,并让您的容器保存该接口。如果你从来没有对你的元素做同样的事情:不要把它们放在同一个容器里。
    【解决方案3】:

    我遇到了同样的问题,但即将使用原语,所以这里建议的解决方案需要工作。 在那种情况下,我帮助我自己:

    args := make([]interface{}, 2)
    args[0] = "some string"
    args[1] = 1 //some int
    

    【讨论】:

      【解决方案4】:

      为了能够初始化,你需要在接口中输入一个类型,而不是一个类型数组,所以建议你修改如下:

          type Pixel struct {
          X float64
          Y float64
      }
      type Pixels []Pixel
      
      type Vertex struct {
          X float64
          Y float64
          Z float64
      }
      type Vertexs []Vertex
      type testpair struct {
          filename string
          values   interface{}
      }
      var tests = map[string]testpair{
          "test1": {
              filename: "file1.csv",
              values: Pixels{
                  Pixel{X: 12.5, Y: 23.4},
                  Pixel{X: 17.2, Y: 7.9}}},
          "test2": {
              filename: "file2.csv",
              values: Vertexs{
                  Vertex{X: 10.7, Y: 13.3, Z: 25.1},
                  Vertex{X: 18.3, Y: 16.9, Z: 16.4}}}}
      

      【讨论】:

      • 这里不需要创建PixelsVertexs 类型,如果你想这样做,你可以这样做values: []Pixel{...}
      • 是的@Adrian 当然你也可以这样做,但只是为了让它更清楚(我通常这样做)
      最近更新 更多