簡體   English   中英

在沒有復制的情況下比較 Go 中的字符串和字節切片

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

檢查 Go 字符串和字節切片是否包含相同字節的最佳方法是什么? 最簡單的str == string(byteSlice)效率低下,因為它首先復制byteSlice

我正在尋找一個以字符串作為參數的Equal(a, b []byte)版本,但找不到任何合適的東西。

從 Go 1.5 開始,編譯器在與使用堆棧分配的臨時字符串進行比較時優化了字符串(字節)。 因此自從 Go 1.5

str == string(byteSlice)

成為將字符串與字節切片進行比較的規范且有效的方法。

如果您對這可能會在以后的版本中中斷這一事實感到滿意(盡管值得懷疑),您可以使用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
}

操場

基准

// 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

Go 編程語言規范

字符串類型

字符串類型表示字符串值的集合。 字符串值是一個(可能是空的)字節序列。 預先聲明的字符串類型是字符串。

可以使用內置函數 len 發現字符串 s 的長度(以字節為單位的大小)。 字符串的字節可以通過整數索引 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

沒有理由使用 unsafe 包或其他東西來比較[]bytestring Go 編譯器現在足夠聰明,它可以優化此類轉換。

這是一個基准

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

👉這里有更多關於優化的信息,還有這個

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM