在Go语言中,如何将未知长度的切片的值赋给结构体?

huangapple go评论81阅读模式
英文:

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

问题

我从GitHub上找到了下面的案例,看起来很丑陋和愚蠢。我认为更好的代码设计可以避免这种情况,但如果我们遇到这种情况,是否可以更简洁地编写呢?

有没有更好的方法来代替通过切片长度进行连续检查呢?

package main

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

func main() {
    set := &NumberSet{SetName: "test"}
    var numbers []int
    // 假设我们不知道切片的实际长度
    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]
    }
}
英文:

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]
    }
}

答案1

得分: 2

你可以使用for range循环遍历数字,这样你就可以省略长度检查,并使用switch语句进行字段赋值,例如:

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

Go Playground上尝试一下。

你还可以将字段的地址列在另一个切片中,并使用单个循环进行赋值:

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

Go Playground上尝试一下。

如果性能不是关键,并且你要赋值的字段是连续的,你可以使用反射来进行赋值,而无需枚举字段,例如:

rv := reflect.ValueOf(set).Elem()
for i, v := range numbers {
    rv.Field(1 + i).Set(reflect.ValueOf(v)) // 1 是 Number1 的偏移量
}

Go Playground上尝试一下。

英文:

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, e.g.:

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.

huangapple
  • 本文由 发表于 2022年7月4日 16:09:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/72853553.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定