ZetCode

Golang slices.IndexFunc

最后修改于 2025 年 4 月 20 日

本教程将介绍如何在 Go 中使用 `slices.IndexFunc` 函数。我们将通过实际示例涵盖切片操作,重点是查找元素。

`slices.IndexFunc` 函数在切片中搜索满足给定条件的第一个元素。它返回第一个匹配项的索引。

如果没有元素满足条件,它将返回 -1。此函数对于查找任何类型切片中的自定义元素非常有用。

基本的 slices.IndexFunc 示例

`slices.IndexFunc` 最简单的用法是查找切片中的第一个负数。我们定义一个测试函数来检查每个元素。

basic_indexfunc.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{1, 2, -3, 4, 5}
    
    idx := slices.IndexFunc(numbers, func(n int) bool {
        return n < 0
    })
    
    fmt.Println("First negative at index:", idx)
}

我们搜索第一个小于零的数字。该函数返回索引 2,即 -3 所在的位置。匿名函数定义了我们的搜索条件。

查找具有特定属性的字符串

`slices.IndexFunc` 可以查找具有特定特征的字符串。此示例查找以“b”开头的第一个字符串。

string_search.go
package main

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

func main() {
    words := []string{"apple", "banana", "cherry", "blueberry"}
    
    idx := slices.IndexFunc(words, func(s string) bool {
        return strings.HasPrefix(s, "b")
    })
    
    fmt.Println("First 'b' word at index:", idx)
}

测试函数使用 `strings.HasPrefix` 来检查每个字符串。它返回索引 1,即找到“banana”的位置,这是第一个匹配的元素。

搜索结构体切片

我们可以将 `slices.IndexFunc` 与自定义结构体类型一起使用。此示例查找切片中第一个 18 岁以下的人。

struct_search.go
package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Alice", 25},
        {"Bob", 30},
        {"Charlie", 17},
        {"Dave", 16},
    }
    
    idx := slices.IndexFunc(people, func(p Person) bool {
        return p.Age < 18
    })
    
    fmt.Println("First minor at index:", idx)
}

该函数检查每个人的年龄字段。它返回索引 2,即找到 Charlie 的位置,尽管 Dave 也未满 18 岁。

不区分大小写的字符串搜索

此示例演示了使用 `IndexFunc` 进行不区分大小写的搜索。我们查找“go”的第一个出现,不区分大小写。

case_insensitive.go
package main

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

func main() {
    langs := []string{"Python", "Go", "Rust", "GO", "Java"}
    
    idx := slices.IndexFunc(langs, func(s string) bool {
        return strings.EqualFold(s, "go")
    })
    
    fmt.Println("First 'go' at index:", idx)
}

`strings.EqualFold` 执行不区分大小写的比较。该函数返回索引 1,即找到“Go”的位置,忽略了稍后索引 3 处的“GO”。

查找具有多个条件的元素

可以在测试函数中组合复杂条件。此示例查找第一个大于 10 的偶数。

multiple_conditions.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{5, 8, 12, 7, 14, 9}
    
    idx := slices.IndexFunc(numbers, func(n int) bool {
        return n > 10 && n%2 == 0
    })
    
    fmt.Println("First even >10 at index:", idx)
}

该条件使用逻辑 AND 组合了两个检查。它返回索引 2,即找到 12 的位置,这是第一个满足两个条件的数字。

处理无匹配项

当没有元素满足条件时,`IndexFunc` 返回 -1。此示例演示了如何处理无匹配项的情况。

no_match.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{1, 3, 5, 7, 9}
    
    idx := slices.IndexFunc(numbers, func(n int) bool {
        return n%2 == 0
    })
    
    if idx == -1 {
        fmt.Println("No even numbers found")
    } else {
        fmt.Println("First even at index:", idx)
    }
}

由于切片只包含奇数,因此函数返回 -1。我们检查此值以正确处理无匹配项的情况。

实际示例:查找可用端口

这个实际示例使用 `IndexFunc` 来查找已使用端口列表中第一个可用的端口。

port_finder.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    usedPorts := []int{80, 443, 8080, 3000, 8000}
    availablePorts := []int{3000, 4000, 5000, 8080, 9000}
    
    idx := slices.IndexFunc(availablePorts, func(p int) bool {
        return !slices.Contains(usedPorts, p)
    })
    
    if idx != -1 {
        fmt.Printf("First available port: %d at index %d\n", 
            availablePorts[idx], idx)
    } else {
        fmt.Println("No available ports found")
    }
}

我们在 `availablePorts` 中搜索第一个不在 `usedPorts` 中的端口。函数返回索引 1,即端口 4000 被发现为可用。

来源

Go 实验性切片包文档

本教程通过实际示例,介绍了 Go 中 `slices.IndexFunc` 函数的使用,重点是在切片中查找具有自定义条件的元素。

作者

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

列出所有 Go 教程