比较Go中的字符串和字节切片而不复制

时间:2015-07-17 18:58:53

标签: go

检查Go字符串和字节切片是否包含相同字节的最佳方法是什么?最简单的str == string(byteSlice)效率低,因为它首先复制byteSlice

我一直在寻找一个Equal(a, b []byte)版本,它以字符串作为参数,但找不到合适的版本。

4 个答案:

答案 0 :(得分:7)

如果你对以后的版本可能会破坏这一事实感到足够舒服(尽管可疑),你可以使用unsafe

func unsafeCompare(a string, b []byte) int {
    abp := *(*[]byte)(unsafe.Pointer(&a))
    return bytes.Compare(abp, b)
}

func unsafeEqual(a string, b []byte) bool {
    bbp := *(*string)(unsafe.Pointer(&b))
    return a == bbp
}

playground

Benchmarks

// using:
//  aaa = strings.Repeat("a", 100)
//  bbb = []byte(strings.Repeat("a", 99) + "b")

// go 1.5
BenchmarkCopy-8         20000000                75.4 ns/op
BenchmarkPetersEqual-8  20000000                83.1 ns/op
BenchmarkUnsafe-8       100000000               12.2 ns/op
BenchmarkUnsafeEqual-8  200000000               8.94 ns/op
// go 1.4
BenchmarkCopy           10000000                233  ns/op
BenchmarkPetersEqual    20000000                72.3 ns/op
BenchmarkUnsafe         100000000               15.5 ns/op
BenchmarkUnsafeEqual    100000000               10.7 ns/op

答案 1 :(得分:5)

从Go 1.5开始,编译器在使用stack-allocated temporary与字符串进行比较时优化字符串(字节)。因此,自从Go 1.5

str == string(byteSlice)

成为将字符串与字节切片进行比较的规范而有效的方法。

答案 2 :(得分:4)

  

The Go Programming Language Specification

     

String types

     

字符串类型表示字符串值的集合。字符串值是a   (可能是空的)字节序列。预先声明的字符串类型是   字符串。

     

可以使用发现字符串s的长度(以字节为单位的大小)   内置函数len。字符串的字节可以通过整数访问   indices 0到len(s)-1。

例如,

package main

import "fmt"

func equal(s string, b []byte) bool {
    if len(s) != len(b) {
        return false
    }
    for i, x := range b {
        if x != s[i] {
            return false
        }
    }
    return true
}

func main() {
    s := "equal"
    b := []byte(s)
    fmt.Println(equal(s, b))
    s = "not" + s
    fmt.Println(equal(s, b))
}

输出:

true
false

答案 3 :(得分:0)

没有理由使用不安全的软件包或仅比较[]bytestring的东西。 Go编译器现在足够聪明了,它可以优化这种转换。

Here's a benchmark

BenchmarkEqual-8                172135624                6.96 ns/op <--
BenchmarkUnsafe-8               179866616                6.65 ns/op <--
BenchmarkUnsafeEqual-8          175588575                6.85 ns/op <--
BenchmarkCopy-8                 23715144                 47.3 ns/op
BenchmarkPetersEqual-8          24709376                 47.3 ns/op

只需将字节片转换为字符串并进行比较:

var (
    aaa = strings.Repeat("a", 100)
    bbb = []byte(strings.Repeat("a", 99) + "b")
)

func BenchmarkEqual(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _ = aaa == string(bbb)
    }
}

?Here is more information about the optimizationthis