2015-07-17 12 views
6

Qual è il modo migliore per verificare che la stringa Go e una slice di byte contengano gli stessi byte? Il più semplice str == string(byteSlice) è inefficiente poiché copia byteSlice prima.Confronta stringa e byte slice in Vai senza copia

Stavo cercando una versione di Equal(a, b []byte) che accetta una stringa come argomento, ma non è riuscita a trovare nulla di adatto.

+1

Non che in Go 1.5 ci "sia" un [strings.Compare] (https://github.com/golang/go/blob/master/src/strings/compare.go), tuttavia è di design estremamente inefficiente . – OneOfOne

risposta

4

A partire da Go 1.5 ottimizza il compilatore stringa (byte) quando si confrontano in una stringa utilizzando un stack-allocated temporary. Così da Go 1.5

str == string(byteSlice) 

è diventato un modo canonico ed efficiente per confrontare la stringa in una sezione di byte.

+0

Anche in 1.7, trovo che confrontare prima le lunghezze è più veloce nel caso in cui siano differenti: 'len (str) == len (byteSlice) && str == stringa (byteSlice)' - sembra che questo sia dovuto al fatto che Go fa la creazione della porzione temporanea (senza allocazione, ma richiede ancora un po 'di tempo) prima di confrontare la lunghezza. – thomasrutter

4

Se siete abbastanza confortevole con il fatto che questo può rompere su una versione successiva (dubbia però), è possibile utilizzare 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

Non penso che non si dovrebbe proporre di usare il pacchetto non sicuro per ottimizzazioni premature. Se l'OP avrebbe dimostrato che la conversione è il collo di bottiglia principale del suo codice, beh forse. – Volker

+0

@Volker ha spiegato che per il suo carico di lavoro 'str == string (byteSlice)' è inefficiente perché lo copia, il che è comprensibile. – OneOfOne

+2

Se non è sul suo percorso caldo, non importa se è inefficiente o molto inefficiente. – Volker

4

The Go Programming Language Specification

String types

Un tipo di stringa rappresenta l'insieme di valori stringa. Un valore stringa è una sequenza di byte (eventualmente vuota). Il tipo di stringa predeclared è la stringa .

La lunghezza di una stringa s (la sua dimensione in byte) può essere rilevata utilizzando len funzione integrata. È possibile accedere ai byte di una stringa dal numero intero indici da 0 a len (s) -1.

Per esempio,

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

uscita:

true 
false 
+2

In assenza di un'implementazione nativa, questo è sufficiente sostituzione universale, soprattutto quando non è prevista una corrispondenza media e il ciclo termina dopo il primo o il secondo carattere –

Problemi correlati