ZetCode

Golang slices.EqualFunc

最后修改于 2025 年 4 月 20 日

本教程解释了如何在 Go 中使用 slices.EqualFunc 函数。我们将通过示例介绍使用自定义相等性函数进行切片比较。

slices.EqualFunc 函数使用自定义相等性函数比较两个切片。它是 Go 实验性 slices 包的一部分。

当您需要切片元素之间的自定义比较逻辑时,此函数非常有用。仅当所有对应元素都相等时,它才返回 true。

基本的 slices.EqualFunc 示例

slices.EqualFunc 最简单的用法是比较两个整数切片。我们定义一个检查数字是否相等的函数。

basic_equal.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    nums1 := []int{1, 2, 3}
    nums2 := []int{1, 2, 3}
    
    equal := slices.EqualFunc(nums1, nums2, func(a, b int) bool {
        return a == b
    })
    
    fmt.Println("Slices are equal:", equal)
}

我们创建两个相同的切片并进行比较。匿名函数定义了我们对每对元素的相等条件。

不区分大小写的字符串比较

slices.EqualFunc 可以不区分大小写地比较字符串。此示例检查两个字符串切片是否包含相同的单词,而不考虑大小写。

case_insensitive.go
package main

import (
    "fmt"
    "slices"
    "strings"
)

func main() {
    words1 := []string{"Apple", "Banana"}
    words2 := []string{"apple", "banana"}
    
    equal := slices.EqualFunc(words1, words2, func(a, b string) bool {
        return strings.EqualFold(a, b)
    })
    
    fmt.Println("Case-insensitive equal:", equal)
}

测试函数使用 strings.EqualFold 进行不区分大小写的比较。尽管大小写不同,但切片被认为是相等的。

按字段比较结构体

我们可以将 slices.EqualFunc 与自定义结构体类型一起使用。此示例按 Age 字段比较 Person 结构体切片。

struct_comparison.go
package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    group1 := []Person{
        {"Alice", 25},
        {"Bob", 30},
    }
    
    group2 := []Person{
        {"Charlie", 25},
        {"Dana", 30},
    }
    
    equal := slices.EqualFunc(group1, group2, func(a, b Person) bool {
        return a.Age == b.Age
    })
    
    fmt.Println("Groups have same ages:", equal)
}

该函数仅比较 Age 字段,忽略姓名。由于它们的年龄序列匹配,因此切片是相等的。

带容差的浮点数比较

对于浮点数,精确相等通常是有问题的。此示例使用基于容差的比较。

float_comparison.go
package main

import (
    "fmt"
    "math"
    "slices"
)

func main() {
    floats1 := []float64{1.0, 2.0, 3.0}
    floats2 := []float64{1.0000001, 1.9999999, 3.0000001}
    
    equal := slices.EqualFunc(floats1, floats2, func(a, b float64) bool {
        return math.Abs(a-b) < 0.0001
    })
    
    fmt.Println("Floats equal within tolerance:", equal)
}

该比较使用一个小的 epsilon 值来考虑浮点数的不精确性。尽管存在微小的差异,但切片被认为是相等的。

比较不同类型

slices.EqualFunc 可以比较不同但兼容类型的切片。此示例将整数与其字符串表示形式进行比较。

type_conversion.go
package main

import (
    "fmt"
    "slices"
    "strconv"
)

func main() {
    nums := []int{1, 2, 3}
    strs := []string{"1", "2", "3"}
    
    equal := slices.EqualFunc(nums, strs, func(n int, s string) bool {
        return strconv.Itoa(n) == s
    })
    
    fmt.Println("Numbers match strings:", equal)
}

该函数将整数转换为字符串进行比较。尽管类型不同,但由于它们的值对应,因此切片是相等的。

空切片和 nil 切片行为

slices.EqualFunc 特别处理空切片和 nil 切片。此示例演示了各种边缘情况。

empty_slices.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    var nilSlice []int
    emptySlice := []int{}
    dataSlice := []int{1, 2, 3}
    
    // Nil vs empty
    fmt.Println("Nil == empty:", 
        slices.EqualFunc(nilSlice, emptySlice, func(a, b int) bool {
            return a == b
        }))
    
    // Nil vs nil
    fmt.Println("Nil == nil:", 
        slices.EqualFunc(nilSlice, nilSlice, func(a, b int) bool {
            return a == b
        }))
    
    // Empty vs data
    fmt.Println("Empty == data:", 
        slices.EqualFunc(emptySlice, dataSlice, func(a, b int) bool {
            return a == b
        }))
}

nil 和空切片被视为彼此相等,但与非空切片不相等。对于空/nil 切片,比较函数永远不会被调用。

实际示例:数据库结果比较

这个实际示例比较数据库查询结果,同时忽略时间戳或 ID 等特定字段。

db_comparison.go
package main

import (
    "fmt"
    "slices"
    "time"
)

type User struct {
    ID        int
    Username  string
    Email     string
    CreatedAt time.Time
}

func main() {
    // Simulated database results
    dbResult1 := []User{
        {1, "alice", "alice@example.com", time.Now()},
        {2, "bob", "bob@example.com", time.Now()},
    }
    
    dbResult2 := []User{
        {3, "alice", "alice@example.com", time.Now().Add(time.Hour)},
        {4, "bob", "bob@example.com", time.Now().Add(time.Hour)},
    }
    
    equal := slices.EqualFunc(dbResult1, dbResult2, func(a, b User) bool {
        return a.Username == b.Username && a.Email == b.Email
    })
    
    fmt.Println("User data matches (excluding IDs/timestamps):", equal)
}

我们在忽略自动生成字段的同时比较用户数据。这展示了自定义相等逻辑的实际用例。

来源

Go 实验性切片包文档

本教程通过各种场景下自定义切片比较的实际示例,介绍了 Go 中的 slices.EqualFunc 函数。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Go 教程