我已经做了很多循环来过滤值,有时甚至将切片转换为带有方便索引的地图来实现这一点,但我觉得这可能不是Go中最好的方法。所以:
考虑以下样板代码,找到第一个名为" Bob"的第一个人,最常用的方法是什么?在people
切片? found
应该是一个bool变量来确定一个名为" Bob"被发现与否。
package main
import "fmt"
type Person struct {
Age int
Name string
}
var people=[]Person{{Age:18,Name:"Deb"},{Age:22,Name:"Bob"},{Age:35,Name:"Bob"}}
func main() {
FirstBob, found := // how to pick first "Bob"?
fmt.Println(FirstBob)
}
更一般:从匹配特定条件的切片中挑选第一个值的最常用方法是什么?
答案 0 :(得分:2)
例如,
package main
import "fmt"
type Person struct {
Age int
Name string
}
var people = []Person{{Age: 18, Name: "Deb"}, {Age: 22, Name: "Bob"}, {Age: 35, Name: "Bob"}}
func findPerson(people []Person, name string) (Person, bool) {
for _, p := range people {
if p.Name == name {
return p, true
}
}
return Person{}, false
}
func main() {
FirstBob, found := findPerson(people, "Bob")
if found {
fmt.Println(FirstBob)
}
}
输出:
{22 Bob}
如果要返回指向Person
结构的指针,
package main
import "fmt"
type Person struct {
Age int
Name string
}
var people = []Person{{Age: 18, Name: "Deb"}, {Age: 22, Name: "Bob"}, {Age: 35, Name: "Bob"}}
func findPerson(people []Person, name string) (*Person, bool) {
for i := range people {
p := &people[i]
if p.Name == name {
return p, true
}
}
return nil, false
}
func main() {
FirstBob, found := findPerson(people, "Bob")
if found {
fmt.Println(*FirstBob)
}
}
输出:
{22 Bob}
答案 1 :(得分:2)
惯用的方法是写出循环 - 例如,Go团队成员(以及前Python编码员)Andrew Gerrand在GopherCon 2014的闭幕演讲中提到了其他功能样式列表处理快捷方式(“过滤器”,“地图”) ,等等)https://www.youtube.com/watch?v=dKGmK_Z1Zl0&t=23m40s
标准的理由是,不使用这些快捷方式会产生更一致的代码(开发人员无法对是否使用map
做出不同的选择),并且它是明确的(当你'时它会更明显)如果循环作为for
块可见,则在大型数据集上执行嵌套循环或循环。
那就是说,1)如果你重复相同类型的搜索很多地方你可能会像在peterSO的答案中那样考虑因素,2)“惯用语”是一个不是所有代码的理想选择一直满足;如果您认为它使您的代码更容易使用,那么没有什么能阻止您编写特定于类型的快捷方式(请注意:type People []Person; func (p People) FirstMatchingIndex(predicate func(p *Person) bool) int {...}
)。例如,标准strings.IndexFunc
接近于“满足谓词的第一项的查找(索引)”。