interface{}转换为[]string

5
我将尝试将一些YAML文件解析为go结构体,但是文件本身不能被视为普通的go结构:一些值可能是字符串或map[string][]string类型。
我尝试的方法是编写自定义的反序列化函数:
func (domain *Domain) UnmarshalYAML(unmarshal func(interface{}) error) error {
    fmt.Println("Parsing domain")

    var hostUrl interface{}
    unmarshal(&hostUrl)
    fmt.Println(reflect.TypeOf(hostUrl))

    switch hostUrl.(type) {
    case string:
        domain.Host = hostUrl.(string)
    case map[interface {}]interface {}:
        fmt.Println("got map")
        v := reflect.ValueOf(hostUrl)
        fmt.Println(v.MapKeys()[0])
        for _, host := range v.MapKeys() {
            domain.Host = host.Interface().(string)

            fmt.Println(v.MapIndex(host)) 
            //HERE I NEED TO DO SMTH LIKE THIS:
            //domain.Urls = v.MapIndex(host).([]string)

        }
    default:
        return errors.New("invalid config file, cant parse domains")
    }

    return nil
}

我的域结构如下:

type Domain struct {
    Host        string
    Urls        []string
}

但是这段代码会导致错误:
invalid type assertion: v.MapIndex(host).([]string) (non-interface type reflect.Value on left) 

所以我的问题可能听起来像“如何将{}接口转换为[]字符串?”或者它可能变得更加复杂:“如果某个键可以是简单字符串或map [string] [] string,如何将YAML文件解析为go结构?”

更新: 回应@mkopriva:

fmt.Println(v.MapIndex(host))
for url := range v.MapIndex(host).Interface().([] interface{}) {
        fmt.Println(url)
}

对我没有帮助,因为它现在只打印一些整数(0),但实际上应该是一个字符串。将其转换为字符串数组会产生另一个错误:

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

1
reflect.Value.MapIndex 不会返回类型为 interface{} 的值,而是返回类型为 reflect.Value 的值,因此类型断言无法编译。 reflect.Value 有一个名为 Interface 的方法,它将其底层值作为 interface{} 返回,您可以在其上进行类型断言。或者,您可以使用 reflect.ValueKind 方法来确定接口的底层类型,然后从那里开始。 - mkopriva
1
请注意,示例代码没有防范可能由于无效类型断言而导致的恐慌,您应该使用“逗号ok”习惯用语来避免这些问题。此外,需要注意的是,您不能将[]interface{}强制转换为[]T,您需要循环处理每个interface{}项并单独进行断言。https://play.golang.org/p/tcig_e8o0bk - mkopriva
在这种情况下,Go 会报告:无效的类型断言:url。(字符串)(左侧为非接口类型int) - Alex Mokeev
这意味着 url 不是接口,因此您不能对该值进行类型断言,正如我在第一条评论中已经提到的那样。它还告诉您实际类型是什么(int),因此如果您想将其存储为字符串,请使用 strconv 包来完成。 - mkopriva
哦不。一切都变得那么容易了。我把迭代做错了:range返回两个值:索引和值本身。 我只捕获了第一个,当然会出现将其转换为字符串的错误。 - Alex Mokeev
显示剩余2条评论
1个回答

5
感谢 @mkopriva 和沙盒中的片段。在迭代 v.MapIndex(host).Interface().([]interface{}) 期间出现整数的原因是 range 返回两个值:索引和相应索引的值。我只捕捉了第一个值,这就是为什么我无法将其强制转换为字符串的原因。
工作循环:
for _, url := range v.MapIndex(host).Interface().([] interface{}) {
    fmt.Println(url.(string))
    domain.Urls = append(domain.Urls,url.(string) )
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接