Подтвердить что ты не робот

Как Go выполняет сравнение строк?

http://golang.org/ref/spec#Comparison_operators

Go поддерживает сравнение строк без каких-либо специальных функций. Выполняет ли run runtime работу за кулисами для сравнения строковых литералов?

4b9b3361

Ответ 1

Как видно из приведенного ниже дампа сборки, сравнение строк делегируется функции runtime.eqstring из среды выполнения (строка 17) после проверки на короткое замыкание, чтобы проверить, являются ли эти два операнда одинаковыми в памяти (строка 11):

$ cat foo.go
package main

func main() {
        a := "hello"
        b := "world"
        _ = a == b
}

$ go tool 6g -S foo.go
--- prog list "main" ---
0000 (foo.go:3) TEXT    main+0(SB),$40-0
0001 (foo.go:3) LOCALS  ,$0
0002 (foo.go:4) LEAQ    go.string."hello"+0(SB),BX
0003 (foo.go:4) MOVQ    (BX),SI
0004 (foo.go:4) MOVQ    8(BX),CX
0005 (foo.go:5) LEAQ    go.string."world"+0(SB),BX
0006 (foo.go:5) MOVQ    (BX),DX
0007 (foo.go:5) MOVQ    8(BX),AX
0008 (foo.go:6) JMP     ,11
0009 (foo.go:6) MOVQ    $1,AX
0010 (foo.go:6) JMP     ,23
0011 (foo.go:6) CMPQ    CX,AX
0012 (foo.go:6) JNE     ,22
0013 (foo.go:6) MOVQ    SI,(SP)
0014 (foo.go:6) MOVQ    CX,8(SP)
0015 (foo.go:6) MOVQ    DX,16(SP)
0016 (foo.go:6) MOVQ    AX,24(SP)
0017 (foo.go:6) CALL    ,runtime.eqstring+0(SB)
0018 (foo.go:6) MOVBQZX 32(SP),BX
0019 (foo.go:6) CMPB    BX,$0
0020 (foo.go:6) JEQ     ,22
0021 (foo.go:6) JMP     ,9
0022 (foo.go:6) MOVQ    $0,AX
0023 (foo.go:7) RET     ,

--- prog list "init" ---
0024 (foo.go:7) TEXT    init+0(SB),$0-0
0025 (foo.go:7) MOVBQZX initdone·+0(SB),AX
0026 (foo.go:7) LOCALS  ,$0
0027 (foo.go:7) CMPB    AX,$0
0028 (foo.go:7) JEQ     ,34
0029 (foo.go:7) CMPB    AX,$2
0030 (foo.go:7) JNE     ,32
0031 (foo.go:7) RET     ,
0032 (foo.go:7) CALL    ,runtime.throwinit+0(SB)
0033 (foo.go:7) UNDEF   ,
0034 (foo.go:7) MOVB    $2,initdone·+0(SB)
0035 (foo.go:7) RET     ,

Если вы не работаете с компилятором или рабочей средой, это не должно вас слишком беспокоить: просто используйте операторы по мере того, как специфицирует spec, и ожидайте, что это сравнение должно быть O (n) с длиной строки.

Ответ 2

runtime/string.goc (go1.3):

func eqstring(s1 String, s2 String) (v bool) {
    if(s1.len != s2.len) {
        v = false;
        return;
    }
    if(s1.str == s2.str) {
        v = true;
        return;
    }
    v = runtime·memeq(s1.str, s2.str, s1.len);
}

int32
runtime·strcmp(byte *s1, byte *s2)
{
    uintptr i;
    byte c1, c2;

    for(i=0;; i++) {
        c1 = s1[i];
        c2 = s2[i];
        if(c1 < c2)
            return -1;
        if(c1 > c2)
            return +1;
        if(c1 == 0)
            return 0;
    }
}

Примечание: разделитель runtime· - это средняя точка Юникода, а не период.