简体   繁体   中英

Assign values from slice of unknown length to struct in Go?

I find the case below from some useful packages in github and it looks so ugly and stupid. I think the better design of code can avoid this, but if we meet this, can it be written more concisely?

Is there a better way to do that instead of continuous checking by slice length?

package main

type NumberSet struct {
    SetName string
    Number1 int
    Number2 int
    Number3 int
}

func main() {
    set := &NumberSet{SetName: "test"}
    var numbers []int
    // assume that we don't know the actual length of slice
    numbers = append(numbers, 1)
    numbers = append(numbers, 2)

    length := len(numbers)
    if length > 0 {
        set.Number1 = numbers[0]
    }
    if length > 1 {
        set.Number2 = numbers[1]
    }
    if length > 2 {
        set.Number3 = numbers[2]
    }
}

You could use a for range to range over the numbers, so you can omit the length check, and use a switch for field assignment, eg:

for i, v := range numbers {
    switch i {
    case 0:
        set.Number1 = v
    case 1:
        set.Number2 = v
    case 2:
        set.Number3 = v
    }
}

Try it on the Go Playground .

You may also list the addresses of the fields in another slice, and use a single loop to do the assignments:

ps := []*int{&set.Number1, &set.Number2, &set.Number3}
for i, v := range numbers {
    *ps[i] = v
}

Try it on the Go Playground .

If performance is not critical and the fields you assign to are sequential, you may use reflection to do the assignments without having to enumerate the fields, for example:

rv := reflect.ValueOf(set).Elem()
for i, v := range numbers {
    rv.Field(1 + i).Set(reflect.ValueOf(v)) // 1 is the offset of Number1
}

Try it on the Go Playground .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM