Несмотря на то, что эта функция сравнения существует в пакете strings
(strings.Compare()
), даже ее документ не рекомендует использовать ее:
Compare возвращает целое число, сравнивая две строки лексикографически.Результат будет 0, если a == b, -1, если a b.
Сравнение включено только для симметрии с байтами пакета.Обычно понятнее и всегда быстрее использовать встроенные операторы сравнения строк ==, <,> и т. Д.
Почему нецелесообразно использовать strings.Compare()
?
Есть несколько причин.
Во-первых, в языках, где этот вид Compare()
является практичным / распространенным, обычно те языки поддерживают сортировку, которая основана именно на функции с этой сигнатурой.
Например, в Java есть интерфейс Comparator
, который вы можете передать Collections.sort()
.Таким образом, в Java вы вынуждены иметь / реализовать такое сравнение (которое возвращает -1
, 0
или 1
).
В 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.
Это означает, что a < b
будет быстрее, чем вызов strings.Compare(a, b)
.
В-третьих, возвращаемое значение strings.Compare()
- это одно целое число, несущее информацию о том, меньше ли a
, чем b
, или равно a
, равно b
, или a
больше, чем b
.Если вам нужно использовать все 3 ветви (не только ветку «меньше» или «равно»), вам обычно необходимо провести дополнительную проверку возвращаемого значения strings.Compare()
, как в этом простом примере:
switch strings.Compare("a", "b") {
case -1:
fmt.Println("less")
case 0:
fmt.Println("equal")
case 1: // or default:
fmt.Println("greater")
}
Теперь, если вы подумаете об этом: сначала выполняется сравнение внутри strings.Compare()
, а затем снова в вашем коде (сравнение возвращаемого значения).Это избыточно и опять менее производительно.
Выше можно написать так (что будет быстрее):
switch {
case a == b:
fmt.Println("equal")
case a < b:
fmt.Println("less")
default:
fmt.Println("greater")
}
Подробнее об эффективности
Как уже говорилось ранее, strings.Compare()
не оптимизировано для преднамеренной производительности.Но библиотеке сортировки Go не требуется результат -1
, 0
, 1
для сортировки строк, а только результат a < b
, который можно получить с той же эффективностью, что и результат Compare()
в другомязыки.
Также обратите внимание, что strings.Compare()
сначала проверяет равенство a == b
, и только если они не равны, продолжается проверка a < b
.Это важно, потому что значения string
в Go хранят длину string
(подробности см. reflect.StringHeader
), что означает, что если 2 строки имеют разную длину, можно сразу решить, что онине равныC и C ++ используют \0
-определенные строковые значения, что означает, что для того, чтобы определить, равны ли 2 строки, всегда требуется сравнивать целые строки, даже если одна - тысяча символов, а другая - на одну меньше.На самом деле это не совсем верно, потому что, если при сравнении символов обнаруживается несоответствие, сравнение заканчивается, но это все равно может быть намного медленнее, чем сравнение двух целых чисел.
Также см. Связанный вопрос: Использованиесимвол == в golang и использование цикла для сравнения, если строка a равна строке b, какая производительность лучше?