去比较字符串

Ric*_*ard 1 string go

给定两个字符串aand b,有时我想确定以下三个语句中的哪一个:a < b, a == bora > b是真的。

在像 C 或 C++ 这样的语言中,我将v在调用相应的函数或方法后得到一个 int 值。然后我可以通过检查是否v < 0,v == 0或来确定上述哪些陈述是正确的v > 0

但是在 Go 中,我必须至少进行两次比较(例如,先测试a < b然后再测试a == b)才能找出三个陈述中的哪一个是正确的。

我的问题是 Go 中有没有一种方法可以让我只做一个比较?

原来这个功能叫做三路比较

icz*_*cza 10

即使这个比较器函数存在于strings包 ( strings.Compare()) 中,即使它的文档也建议不要使用它:

比较返回按字典顺序比较两个字符串的整数。如果 a==b,则结果为 0,如果 a < b,则结果为 -1,如果 a > b,则结果为 +1。

比较仅用于包字节的对称性。使用内置的字符串比较运算符 ==、<、> 等通常更清晰、更快。

为什么不实用strings.Compare()

有几个原因。

首先,在这种Compare()实用/常见的语言中,通常这些语言支持完全建立在具有此签名的函数上的排序。

例如,在 Java 中有Comparator您可以传递给Collections.sort(). 因此,在 Java 中,您被迫拥有/实现这种比较(即返回-1,01)。

在 Go 中,排序不是基于这样的比较器函数。在 Go 中,排序基于一个Less(i, j int) bool基本上是a[i] < a[j]比较的函数,它只是“它更少吗?”。为此,您不需要strings.Compare(),您只需要a < b。例如,请参阅sort.Slice()

第二个原因:strings.Compare()没有刻意优化,所以你不习惯使用它。的实现strings.Compare()有这样的评论:

// NOTE(rsc): This function does NOT call the runtime cmpstring function,
// because we do not want to provide any performance justification for
// using strings.Compare. Basically no one should use strings.Compare.
// As the comment above says, it is here only for symmetry with package bytes.
// If performance is important, the compiler should be changed to recognize
// the pattern so that all code doing three-way comparisons, not just code
// using strings.Compare, can benefit.
Run Code Online (Sandbox Code Playgroud)

这意味着这a < b将比调用strings.Compare(a, b).

第三, 的返回值strings.Compare()是单个整数,携带是否a小于ba等于ba大于的信息b。如果您确实需要使用所有 3 个分支(不仅仅是“less”或“equal”分支),您通常需要进一步检查 的返回值strings.Compare(),就像这个简单的例子:

switch strings.Compare("a", "b") {
case -1:
    fmt.Println("less")
case 0:
    fmt.Println("equal")
case 1: // or default:
    fmt.Println("greater")
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您考虑一下:首先在 内部执行比较strings.Compare(),然后在您的代码中再次执行(比较返回值)。这是多余的,而且性能也较低。

上面可以这样写(这样会更快):

switch {
case a == b:
    fmt.Println("equal")
case a < b:
    fmt.Println("less")
default:
    fmt.Println("greater")
}
Run Code Online (Sandbox Code Playgroud)

更多关于效率

如前所述,strings.Compare()不是故意针对性能进行优化的。但是 Go 的排序库不需要-1, 0,1结果来对字符串进行排序,只需要 的结果a < b,可以获得与Compare()其他语言中获取结果相同的效率。

另请注意,strings.Compare()首先检查是否相等a == b,并且仅当它们不相等时才进行检查a < b。这很重要,因为stringGo 中的值存储了string(有关详细信息,请参阅reflect.StringHeader)的长度,这意味着如果 2 个字符串具有不同的长度,可以立即确定它们不相等。C 和 C++ 使用 -\0终止的字符串值,这意味着判断 2 个字符串是否相等总是需要比较整个字符串,即使一个是一千个字符,另一个少一个。实际上这并不完全正确,因为如果在比较字符时检测到不匹配,则比较结束,但这可能仍然比比较 2 个整数慢很多。

另请参阅相关问题:在golang中使用==符号并使用循环来比较字符串a是否等于字符串b,哪个性能更好?

  • 如果您在 C 或 C++ 中使用比较函数,则只需比较这两个字符串一次,然后与整数进行比较。对于 golang,您必须比较它们两次(使用 strings.Compare() 或不使用)。所以理论上来说,golang的运行时间会比C/C++的情况长一倍。 (2认同)