You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Go的slices.BinarySearchFunc会两次调用匹配元素的比较函数?

关于slices.BinarySearchFunc比较函数多次调用的疑问

我在调试传入slices.BinarySearchFunc的比较函数时,发现匹配元素的日志被打印了两次,对此感到好奇。

复现代码

package main

import (
    "cmp"
    "log"
    "slices"
    "testing"

    "github.com/stretchr/testify/assert"
)

func init() {
    log.SetFlags(0)
}

func Test(t *testing.T) {
    numbers := []int{
        1, 2, 3,
    }
    timesCalled := 0
    comparisonFunc := func(l, r int) int {
        timesCalled++
        log.Printf("Comparing %d and %d", l, r)
        result := cmp.Compare(l, r)
        if result == 0 {
            log.Printf("Matched %d and %d", l, r)
        }
        return result
    }
    if idx, found := slices.BinarySearchFunc(numbers, 2, comparisonFunc); found {
        assert.Equal(t, 2, numbers[idx])
    } else {
        assert.Fail(t, "Number not found")
    }
    assert.LessOrEqual(t, timesCalled, 2)
}

输出结果

=== RUN   Test
Comparing 2 and 2
Matched 2 and 2
Comparing 1 and 2
Comparing 2 and 2
Matched 2 and 2
    prog_test.go:35: 
            Error Trace:    /tmp/sandbox3165947586/prog_test.go:35
            Error:          "3" is not less than or equal to "2"
            Test:           Test
--- FAIL: Test (0.00s)
FAIL

Program exited.

问题解答

1. 该行为是否符合预期?

是,这个行为完全符合预期。slices.BinarySearchFunc的底层实现遵循标准二分查找逻辑,其设计目标是返回第一个匹配元素的索引(当数组存在多个相同元素时)。因此,即使在中间步骤找到匹配项,算法仍会继续调整左右边界,确认左半部分是否存在更早的匹配元素,这就导致了比较函数被多次调用。

在你的测试用例中,目标元素2位于数组中间,第一次匹配后,算法会继续检查左半区间,因此触发了第二次比较调用。

2. 能否让比较函数找到匹配后立即停止?

无法通过标准库的slices.BinarySearchFunc实现这一点,因为该函数必须完成完整的边界确认流程来保证返回索引的正确性。

如果你的场景仅需要快速判断元素是否存在,不需要定位第一个匹配项,可以自行实现简化版的二分查找,在首次匹配时直接返回结果:

func quickBinarySearchFunc[S ~[]E, E any](x S, target E, cmp func(E, E) int) (int, bool) {
    low, high := 0, len(x)
    for low < high {
        mid := (low + high) / 2
        c := cmp(x[mid], target)
        if c == 0 {
            return mid, true
        } else if c < 0 {
            low = mid + 1
        } else {
            high = mid
        }
    }
    return low, false
}

注意:这个简化版本在存在多个相同元素时,返回的可能不是第一个匹配项的索引,仅适用于只需要确认存在性的场景。


内容的提问来源于stack exchange,提问作者Jacob Wan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 11:40:06