Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

interface{} to []string

Tags:

yaml

go

I'm trying to parse some YAML file into go struct, but the file itself can not be treated as ordinary go structure: some of values may be either string or map[string][]string.

What I have tried is to do custom unmarshal func:

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
}

My domain structure looks like this:

type Domain struct {
    Host        string
    Urls        []string
}

But this code causes an error:

invalid type assertion: v.MapIndex(host).([]string) (non-interface type reflect.Value on left) 

So my question may sound like "how to convert {}interface to []string?" or it may become more complex: "How to parse YAML file into go struct if some key can be either simple string or map[string][]string?"

UPDATE: Responding to @mkopriva:

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

Didnt help me, as now it just prints some integers (0), but there should be a string. Converting it to an array of strings throws another error:

panic: interface conversion: interface {} is []interface {}, not []string
like image 333
Alex Mokeev Avatar asked Jan 28 '18 15:01

Alex Mokeev


People also ask

What is [] interface {} Golang?

The interface type that specifies zero methods is known as the empty interface: interface{} An empty interface may hold values of any type. (Every type implements at least zero methods.) Empty interfaces are used by code that handles values of unknown type.

How to convert interface to string in java?

Use fmt. Sprintf to convert an interface value to a string. In fact, the same technique can be used to get a string representation of any data structure.

How to change interface to string in Golang?

To convert interface to string in Go, use fmt. Sprint function, which gets the default string representation of any value. If you want to format an interface using a non-default format, use fmt. Sprintf with %v verb.

What is type assertion in Golang?

A type assertion provides access to an interface value's underlying concrete value. t := i.(T) This statement asserts that the interface value i holds the concrete type T and assigns the underlying T value to the variable t . If i does not hold a T , the statement will trigger a panic.


1 Answers

Thanks to @mkopriva and the snippet from the sandbox. The reason of integer appearing during iterating over v.MapIndex(host).Interface().([] interface{}) is that range returns two values: index and corresponding to that index value. I was only catching the first one. It is why I wasn't able to cast it to string.

Working loop:

for _, url := range v.MapIndex(host).Interface().([] interface{}) {
    fmt.Println(url.(string))
    domain.Urls = append(domain.Urls,url.(string) )
}
like image 114
Alex Mokeev Avatar answered Nov 15 '22 05:11

Alex Mokeev