无法在 Go 中将 []interface{} 转换为 []string

Can't convert []interface{} to []string in Go

XY 问题: 我正在尝试读取如下所示的 YAML 文件,并输出一组组合了 YAML 文件中某些键和值的元组.例如。鉴于此 YAML 数据:

---
fruit:
    apple:
        colour:
            - green
    'banana':
        colour:
            - yellow
    pear:
        colour:
            - green
            - yellow

我想将“水果”下的每个键与“颜色”下的每个值组合成元组。我的元组看起来像这样:

apple:green
banana:yellow
pear:green
pear:yellow

为此,我使用映射[string]接口{}将我的 YAML 数据解组为 Go - 我不能使用结构,因为“fruit”下面的键的名称可能是任何东西,所以我需要使用动态类型。到目前为止,这是我的代码:

package main

import (
    "fmt"
    "log"

    "gopkg.in/yaml.v3"
)

var data string = `
---
fruit:
    apple:
        colour:
            - green
    'banana':
        colour:
            - yellow
    pear:
        colour:
            - green
            - yellow
`

func main() {
    m := make(map[string]interface{})
    err := yaml.Unmarshal([]byte(data), &m)
    if err != nil {
        log.Fatal("Failed to parse YAML file")
    }

    for _, v := range m {
        fruits := v.(map[string]interface{})
        for fruit, v2 := range fruits {
            colours := v2.(map[string]interface{})["colour"]
            for colour := range colours {
                fmt.Println("%v:%v\n", fruit, colour)
            }
        }
    }
}

游乐场link:https://go.dev/play/p/v8iuzmMLtjX

问题是 for colour := range colours - 我收到错误:

cannot range over colours (type interface {})

我发现 说我不能直接将 []interface{} 转换为 []string,而必须迭代这些值。这就是我在这里尝试做的。 v2 变量计算出 map[string]interface {} 类型,例如可以是 map[colour:[green yellow]]。然后我尝试将其转换为另一个 map[string]interface{} 以获得“颜色”的值,它计算出 []interface{} 类型 [green yellow] 并存储在 colours变量。

但出于某种原因我无法遍历 colours。我不明白我的解决方案和 icza's solution in the linked answer(我已经 link编辑了他们的 Playground link)有什么不同。 colours 在我的解决方案中的数据类型是 []interface{},在 icza 的解决方案中 t 的数据类型也是 []interface{} - 但在这种情况下可以迭代切片并访问其中的值。

我尝试的另一个解决方案来自 ,它尝试直接将 []interface{} 转换为 []string:

c := colours.([]string)

那也没有用:

panic: interface conversion: interface {} is []interface {}, not []string

我需要做什么才能使这个解决方案起作用?

因为在编译时只有映射的键是未知的,但是结构已知的,所以你可以比map[string]interface{}:

更具体
type Document struct {
    Fruits map[string]Fruit `yaml:"fruit"`
}

type Fruit struct {
    Colours []string `yaml:"colour"`
}

这使得建立您的价值观变得微不足道:

package main

import (
    "fmt"

    "gopkg.in/yaml.v3"
)


var data string = `
---
fruit:
    apple:
        colour:
            - green
    'banana':
        colour:
            - yellow
    pear:
        colour:
            - green
            - yellow
`

func main() {
    var m Document
    yaml.Unmarshal([]byte(data), &m)

    for name, fruit := range m.Fruits {
        for _, colour := range fruit.Colours {
            fmt.Printf("%s:%s\n", name, colour)
        }
    }
}

在操场上试试:https://go.dev/play/p/phnvRriQmMh

感谢 Cerise Limón 提供的更正帮助我修正了我的解决方案!

package main

import (
    "fmt"
    "log"

    "gopkg.in/yaml.v3"
)

var data string = `
---
fruit:
    apple:
        colour:
            - green
    'banana':
        colour:
            - yellow
    pear:
        colour:
            - green
            - yellow
`

func main() {
    m := make(map[string]interface{})
    err := yaml.Unmarshal([]byte(data), &m)
    if err != nil {
        log.Fatal("Failed to parse YAML file")
    }

    for _, v := range m {
        fruits := v.(map[string]interface{})
        for fruit, v2 := range fruits {
            colours := v2.(map[string]interface{})["colour"]
            c := colours.([]interface{})
            for _, colour := range c {
                cs := colour.(string)
                fmt.Printf("%v:%v\n", fruit, cs)
            }
        }
    }
}

https://go.dev/play/p/dZT84tDLMjE