Using the == symbol in golang and using a loop to compare if string a equals string b,which performance is better?

余生颓废 提交于 2019-12-23 06:29:07

问题


for i:=0;i<len(a);i++{
    if a[i] != b[i]{
        return false
    }
}

and just

a == b

I've found that the same string have different address

a := "abc"
b := "abc"
println(&a)
println(&b)

answer is :
0xc420045f68
0xc420045f58

so == not using address to compare.
In fact, I would like to know how == compares two strings.
I am searching for a long time on net. But failed...


回答1:


You should use the == operator to compare strings. It compares the content of the string values.

What you print is the address of a and b variables. Since they are 2 distinct non-zero size variables, their addresses cannot be the same by definition. The values they hold of course may or may not be the same. The == operator compares the values the variables hold, not the addresses of the variables.

Your solution with the loop might even result in a runtime panic, if the b string is shorter than a, as you index it with values that are valid for a.

The built-in == operator will likely always outperform any loop, as that is implemented in architecture specific assembly code. It is implemented in the runtime package, unexported function memequal().

Also note that the built-in comparison might even omit checking the actual contents of the texts if their string header points to the same data (and have equal length). There is no reason not to use ==.

The only reason where a custom equal function for string values would make sense is where the heuristics of your strings are known. E.g. if you know all the string values have the same prefix and they may only differ in their last character. In this case you could write a comparator function which only compares the last character of the strings to decide if they are equal (and only, optionally revert to actually compare the rest). This solution would of course not use a loop.




回答2:


Use the Go == operator for string equality. The Go gc and gccgo compilers are optimizing compilers. The Go runtime has been optimized.


This comment in the strings package documentation for the strings.Compare function is also relevant to equality:

Compare is included only for symmetry with package bytes. It is usually clearer and always faster to use the built-in string comparison operators ==, <, >, and so on.


In Go, the runtime representation of a string is a struct:

type StringHeader struct {
        Data uintptr    // byte array pointer
        Len  int        // byte array length
}

When you assign a Go string value to a variable,

s := "ABC"

the memory location allocated for the variable s is set to the value of a StringHeader struct describing the string. The address of the variable, &s, points to the struct, not to the underlying byte array.

A comparison for Go string equality compares the bytes of the underlying arrays, the values of *StringHeader.Data[0:StringHeader.Len].


In Go, we use the Go testing package to benchmark performance. For example, comparing the Go == operator to two Go string equality functions:

Output:

$ go test equal_test.go -bench=. -benchmem
BenchmarkEqualOper-4     500000000    3.19 ns/op    0 B/op    0 allocs/op
BenchmarkEqualFunc1-4    500000000    3.32 ns/op    0 B/op    0 allocs/op
BenchmarkEqualFunc2-4    500000000    3.61 ns/op    0 B/op    0 allocs/op
$ go version
go version devel +bb222cde10 Mon Jun 11 14:47:06 2018 +0000 linux/amd64
$

equal_test.go:

package main

import (
    "reflect"
    "testing"
    "unsafe"
)

func EqualOper(a, b string) bool {
    return a == b
}

func EqualFunc1(a, b string) bool {
    if len(a) != len(b) {
        return false
    }
    for i := 0; i < len(a); i++ {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

func EqualFunc2(a, b string) bool {
    if len(a) != len(b) {
        return false
    }
    if len(a) == 0 {
        return true
    }
    // string intern equality
    if (*reflect.StringHeader)(unsafe.Pointer(&a)).Data == (*reflect.StringHeader)(unsafe.Pointer(&b)).Data {
        return true
    }
    for i := 0; i < len(a); i++ {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

var y, z = "aby", "abz"

func BenchmarkEqualOper(B *testing.B) {
    a, b := y, z
    for i := 0; i < B.N; i++ {
        _ = EqualOper(a, b)
    }
}

func BenchmarkEqualFunc1(B *testing.B) {
    a, b := y, z
    for i := 0; i < B.N; i++ {
        _ = EqualFunc1(a, b)
    }
}

func BenchmarkEqualFunc2(B *testing.B) {
    a, b := y, z
    for i := 0; i < B.N; i++ {
        _ = EqualFunc2(a, b)
    }
}


来源:https://stackoverflow.com/questions/50792777/using-the-symbol-in-golang-and-using-a-loop-to-compare-if-string-a-equals-str

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!