在Go语言中,可以将字段(而不是其值)作为参数传递吗?

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

Is it possible to pass a field (not its value) as an argument in golang?

问题

我有一个程序,根据结构体切片中的不同字段创建不同的排行榜。这需要根据不同的字段对切片进行多次排序,唯一变化的是比较的字段。

有没有办法通过将字段(而不是其值)作为参数传递给函数来封装这个重复的逻辑?

为了澄清,这是我目前采用的大致方法:

type Person struct {
	Name  string
	Stat1 int
	Stat2 float64
}

person1 := Person{"Alice", 10, 2.0}
person2 := Person{"Bob", 12, 1.0}
person3 := Person{"Zach", 14, 0.1}

people := []Person{person1, person2, person3}

// 根据一个字段进行排序
sort.Slice(people, func(i, j int) bool { 
    // 依赖于比较 Stat1 字段的比较逻辑
})
for i, p := range people {
	fmt.Println(fmt.Sprint(i+1) + " - " + p.Name + " with " + fmt.Sprint(people[i].Stat1))
}

// 根据另一个字段进行排序
sort.Slice(people, func(i, j int) bool { 
    // 依赖于比较 Stat2 字段的比较逻辑,但与上面的比较逻辑完全相同
})
for i, p := range people {
	fmt.Println(fmt.Sprint(i+1) + " - " + p.Name + " with " + fmt.Sprintf("%.1f", people[i].Stat2))
}

// 还有很多很多这样的代码...

理想情况下,我希望能够像这样做(但我认为这可能在没有泛型的情况下是不可能的):

func sortSliceByField(people []Person, fieldToSortOn PersonField) []Person {
    // 在参数中传递的字段上重复的排序逻辑
}
英文:

I have a program that is creating different leaderboards based on different fields in a slice of structs. This requires sorting the slice many times based on different fields where the only thing that is changing in the logic is the field being compared.

Is there a way to encapsulate this repeated logic by passing a field (not its value) as an argument to a function?

For clarification, here is rough approximation of the approach I am taking now:

type Person struct {
	Name  string
	Stat1 int
	Stat2 float64
}

person1 := Person{"Alice", 10, 2.0}
person2 := Person{"Bob", 12, 1.0}
person3 := Person{"Zach", 14, 0.1}

people := []Person{person1, person2, person3}

// Sorting based on one field
sort.Slice(people, func(i, j int) bool { 
    // Comparison logic that depends on comparing the Stat1 field
})
for i, p := range people {
	fmt.Println(fmt.Sprint(i+1) + " - " + p.Name + " with " + fmt.Sprint(people[i].Stat1))
}

// Sorting based on another field
sort.Slice(people, func(i, j int) bool { 
    // Comparison logic that depends on comparing the Stat2 field
    // but is otherwise identical to the comparison logic above
})
for i, p := range people {
	fmt.Println(fmt.Sprint(i+1) + " - " + p.Name + " with " + fmt.Sprintf("%.1f", people[i].Stat2))
}

// Many, many more of these...

Ideally I'd be able to do something like this (but think this may be impossible without generics):

func sortSliceByField(people []Person, fieldToSortOn PersonField) []Person {
    // Repeated sort logic on the field passed as an argument
}

答案1

得分: 1

你展示的代码的重复性不会从你提出的解决方案中受益。然而,你可以通过使用类似以下的结构使其更加结构化:

var SortOptions = map[string]func([]Person) func(int,int)bool {
  "stat1": func(people []Person) func(int,int) bool { 
     return func(i,j int) bool { return people[i].Stat1<people[j].Stat1 }
   },
  "stat2": func(people []Person) func(int,int) bool {
     return func(i,j int) bool { return people[i].Stat2<people[j].Stat2 }
   },
}

然后你可以这样做:

sort.Slice(people,SortOptions["stat1"](people))
英文:

The repetitiveness of the code you displayed would not benefit from the solution you propose. However, you can make it a bit more structured by using something like this:

var SortOptions = map[string]func([]Person) func(int,int)bool {
  &quot;stat1&quot;: func(people []Person) func(int,int) bool { 
     return func(i,j int) bool { return people[i].Stat1&lt;people[j].Stat1 }
   },
  &quot;stat2&quot;: func(people []Person) func(int,int) bool {
     return func(i,j int) bool { return people[i].Stat2&lt;people[j].Stat2 }
   },
}

Then you can do:

sort.Slice(people,SortOptions[&quot;stat1&quot;](people))

huangapple
  • 本文由 发表于 2021年5月27日 11:19:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/67715222.html
匿名

发表评论

匿名网友

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

确定