2015-07-17 20 views
6

Cách tốt nhất để kiểm tra xem chuỗi Go và một lát byte có chứa cùng một byte không? Các đơn giản nhất str == string(byteSlice) là không hiệu quả vì nó sao chép byteSlice đầu tiên.So sánh chuỗi và byte slice trong Go mà không cần sao chép

Tôi đang tìm kiếm phiên bản Equal(a, b []byte) để lấy chuỗi làm đối số của nó, nhưng không thể tìm thấy bất kỳ điều gì phù hợp.

+1

Không phải trong Go 1.5 có "là" một [strings.Compare] (https://github.com/golang/go/blob/master/src/strings/compare.go), tuy nhiên đó là do thiết kế cực kỳ kém hiệu quả . – OneOfOne

Trả lời

4

Bắt đầu từ Go 1.5 trình biên dịch tối ưu hóa chuỗi (byte) khi so sánh với một chuỗi sử dụng một stack-allocated temporary. Do đó kể từ khi Đi 1.5

str == string(byteSlice) 

trở thành một cách kinh điển và hiệu quả để so sánh chuỗi với một lát byte.

+0

Ngay cả trong 1.7, tôi thấy rằng so sánh độ dài đầu tiên là nhanh hơn trong trường hợp chúng khác nhau: 'len (str) == len (byteSlice) && str == chuỗi (byteSlice)' - có vẻ như điều này là bởi vì Go tạo ra của lát tạm thời (không có phân bổ, nhưng vẫn mất một ít thời gian) trước khi so sánh độ dài. – thomasrutter

4

Nếu bạn đủ thoải mái với thực tế rằng đây có thể phá vỡ trên một thông cáo sau (nghi ngờ mặc dù), bạn có thể sử dụng 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 
+3

Tôi không nghĩ rằng người ta không nên đề xuất sử dụng gói không an toàn để tối ưu hóa sớm. Nếu OP có thể chứng minh rằng việc chuyển đổi là nút cổ chai chính của mã của anh ta, thì có thể. – Volker

+0

@Volker ông giải thích rằng đối với khối lượng công việc của mình 'str == string (byteSlice)' là không hiệu quả vì nó sao chép nó, đó là dễ hiểu. – OneOfOne

+2

Nếu nó không phải là trên con đường nóng của mình nó chỉ không quan trọng nếu nó không hiệu quả hoặc rất kém hiệu quả. – Volker

4

The Go Programming Language Specification

String types

Loại chuỗi đại diện cho tập các giá trị chuỗi. Giá trị chuỗi là một chuỗi byte có thể là (có thể trống). Loại chuỗi được khai báo trước là chuỗi.

Độ dài của một chuỗi s (kích thước bằng byte) có thể được khám phá bằng cách sử dụng hàm số len tích hợp sẵn trong số . Một chuỗi của chuỗi có thể được truy cập bằng số nguyên chỉ số 0 đến len (s) -1.

Ví dụ,

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 
+2

Trong trường hợp không có một bản địa thực hiện này là đủ tốt thay thế phổ biến đặc biệt là khi trận đấu trung bình là không mong đợi và vòng lặp chấm dứt sau khi ký tự đầu tiên hoặc thứ hai –

Các vấn đề liên quan