Golang slices.MaxFunc
最后修改于 2025 年 4 月 20 日
本教程解释了如何在 Go 中使用 slices.MaxFunc 函数。我们将涵盖使用自定义比较函数查找最大元素。
slices.MaxFunc 函数根据自定义比较函数返回切片中的最大元素。它是 Go 实验性 slices 包的一部分。
当您需要根据自定义标准而不是自然排序来查找“最大”元素时,此函数非常有用。如果切片为空,它会 panic。
基本的 slices.MaxFunc 示例
slices.MaxFunc 最简单的用法是查找切片中的最大数字。我们提供一个比较两个整数的比较函数。
package main
import (
"fmt"
"slices"
)
func main() {
numbers := []int{3, 1, 4, 1, 5, 9, 2, 6}
max := slices.MaxFunc(numbers, func(a, b int) int {
if a < b {
return -1
} else if a > b {
return 1
}
return 0
})
fmt.Println("Maximum number:", max)
}
我们创建一个数字切片,并使用比较函数找到最大值。如果 a < b,则函数返回 -1;如果 a > b,则返回 1;如果它们相等,则返回 0。
查找最长的字符串
slices.MaxFunc 可以查找切片中最长的字符串。此示例通过字符串长度比较字符串。
package main
import (
"fmt"
"slices"
)
func main() {
words := []string{"apple", "banana", "cherry", "date"}
longest := slices.MaxFunc(words, func(a, b string) int {
if len(a) < len(b) {
return -1
} else if len(a) > len(b) {
return 1
}
return 0
})
fmt.Println("Longest word:", longest)
}
比较函数检查字符串长度而不是字典顺序。“banana”是返回的最长字符串,长度为 6 个字符。
使用结构体
我们可以将 slices.MaxFunc 与自定义结构类型一起使用。此示例查找切片中最年长的人。
package main
import (
"fmt"
"slices"
)
type Person struct {
Name string
Age int
}
func main() {
people := []Person{
{"Alice", 25},
{"Bob", 30},
{"Charlie", 17},
}
oldest := slices.MaxFunc(people, func(a, b Person) int {
if a.Age < b.Age {
return -1
} else if a.Age > b.Age {
return 1
}
return 0
})
fmt.Println("Oldest person:", oldest)
}
该函数通过 Age 字段比较 Person 结构。Bob 是返回的最年长的人,年龄为 30 岁。
自定义比较逻辑
可以在函数中实现复杂的比较逻辑。此示例查找绝对值最大的数字。
package main
import (
"fmt"
"math"
"slices"
)
func main() {
numbers := []int{-5, 2, -8, 3, 1}
maxAbs := slices.MaxFunc(numbers, func(a, b int) int {
absA := math.Abs(float64(a))
absB := math.Abs(float64(b))
if absA < absB {
return -1
} else if absA > absB {
return 1
}
return 0
})
fmt.Println("Number with largest absolute value:", maxAbs)
}
比较函数首先计算绝对值,然后进行比较。返回 -8,因为它的绝对值最大(8)。
处理空切片
slices.MaxFunc 在空切片上调用时会 panic。此示例显示如何安全地处理这种情况。
package main
import (
"fmt"
"slices"
)
func main() {
var empty []int
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
// This will panic
_ = slices.MaxFunc(empty, func(a, b int) int {
if a < b {
return -1
} else if a > b {
return 1
}
return 0
})
fmt.Println("This line won't be reached")
}
我们使用 defer 和 recover 来优雅地处理 panic。在生产代码中调用 MaxFunc 之前,请务必检查切片长度。
按多个字段查找最大值
我们可以使用多个字段来实现复杂的比较逻辑。此示例查找得分最高的学生,以姓名作为平局决定因素。
package main
import (
"fmt"
"slices"
"strings"
)
type Student struct {
Name string
Score int
}
func main() {
students := []Student{
{"Alice", 85},
{"Bob", 92},
{"Charlie", 85},
{"Diana", 92},
}
topStudent := slices.MaxFunc(students, func(a, b Student) int {
if a.Score < b.Score {
return -1
} else if a.Score > b.Score {
return 1
}
// Tiebreaker: compare names alphabetically
return strings.Compare(a.Name, b.Name)
})
fmt.Printf("Top student: %s with score %d\n", topStudent.Name, topStudent.Score)
}
当分数相同时,比较将回退到按字母顺序排列的姓名。Bob 是返回的最高分学生,在姓名比较中击败了 Diana。
实际示例:最新文件
这个实际示例查找目录中修改时间最近的文件。我们通过修改时间戳比较文件。
package main
import (
"fmt"
"os"
"slices"
"time"
)
func main() {
files := []string{"file1.txt", "file2.txt", "file3.txt"}
fileInfos := make([]os.FileInfo, 0, len(files))
for _, f := range files {
fi, err := os.Stat(f)
if err != nil {
fmt.Printf("Error reading %s: %v\n", f, err)
continue
}
fileInfos = append(fileInfos, fi)
}
if len(fileInfos) == 0 {
fmt.Println("No valid files found")
return
}
latest := slices.MaxFunc(fileInfos, func(a, b os.FileInfo) int {
aTime := a.ModTime()
bTime := b.ModTime()
if aTime.Before(bTime) {
return -1
} else if aTime.After(bTime) {
return 1
}
return 0
})
fmt.Printf("Latest file: %s (modified at %v)\n", latest.Name(), latest.ModTime())
}
我们首先收集文件信息,然后找到修改时间最新的文件。该示例会优雅地处理错误和空结果。
来源
本教程介绍了 Go 中的 slices.MaxFunc 函数,并提供了使用自定义比较函数查找最大元素的实际示例。