简体   繁体   English

在没有复制的情况下比较 Go 中的字符串和字节切片

[英]Compare string and byte slice in Go without copy

What is the best way to check that Go string and a byte slice contain the same bytes?检查 Go 字符串和字节切片是否包含相同字节的最佳方法是什么? The simplest str == string(byteSlice) is inefficient as it copies byteSlice first.最简单的str == string(byteSlice)效率低下,因为它首先复制byteSlice

I was looking for a version of Equal(a, b []byte) that takes a string as its argument, but could not find anything suitable.我正在寻找一个以字符串作为参数的Equal(a, b []byte)版本,但找不到任何合适的东西。

Starting from Go 1.5 the compiler optimizes string(bytes) when comparing to a string using a stack-allocated temporary .从 Go 1.5 开始,编译器在与使用堆栈分配的临时字符串进行比较时优化了字符串(字节)。 Thus since Go 1.5因此自从 Go 1.5

str == string(byteSlice)

became a canonical and efficient way to compare string to a byte slice.成为将字符串与字节切片进行比较的规范且有效的方法。

If you're comfortable enough with the fact that this can break on a later release (doubtful though), you can use unsafe :如果您对这可能会在以后的版本中中断这一事实感到满意(尽管值得怀疑),您可以使用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

The Go Programming Language Specification Go 编程语言规范

String types字符串类型

A string type represents the set of string values.字符串类型表示字符串值的集合。 A string value is a (possibly empty) sequence of bytes.字符串值是一个(可能是空的)字节序列。 The predeclared string type is string.预先声明的字符串类型是字符串。

The length of a string s (its size in bytes) can be discovered using the built-in function len.可以使用内置函数 len 发现字符串 s 的长度(以字节为单位的大小)。 A string's bytes can be accessed by integer indices 0 through len(s)-1.字符串的字节可以通过整数索引 0 到 len(s)-1 访问。

For example,例如,

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))
}

Output:输出:

true
false

There is no reason to use the unsafe package or something just to compare []byte and string .没有理由使用 unsafe 包或其他东西来比较[]bytestring The Go compiler is clever enough now, and it can optimize such conversions. 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

Just convert a byte slice to a string and compare:只需将字节切片转换为字符串并进行比较:

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 optimization , and this . 👉这里有更多关于优化的信息,还有这个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM