Welche Methode ist am besten (am idiomatischsten) für das Testen von nicht leeren Zeichenketten (in Go)?
if len(mystring) > 0 { }
Oder:
if mystring != "" { }
Oder etwas anderes?
Welche Methode ist am besten (am idiomatischsten) für das Testen von nicht leeren Zeichenketten (in Go)?
if len(mystring) > 0 { }
Oder:
if mystring != "" { }
Oder etwas anderes?
Gemäß den offiziellen Richtlinien und aus Leistungssicht scheinen sie äquivalent zu sein (Antwort von ANisus), das s != "" wäre aufgrund eines syntaktischen Vorteils besser. s != "" wird zur Kompilierzeit fehlschlagen, wenn die Variable kein String ist, während len(s) == 0 für verschiedene andere Datentypen erfolgreich sein wird.
Ich denke == ""
ist schneller und lesbarer.
package main
import(
"fmt"
)
func main() {
n := 1
s:=""
if len(s)==0{
n=2
}
fmt.Println("%d", n)
}
Wenn dlv debug playground.go
mit len(s) und =="" verglichen wird, bekomme ich diese Situation s == ""
playground.go:6 0x1008d9d20 810b40f9 MOVD 16(R28), R1
playground.go:6 0x1008d9d24 e28300d1 SUB $32, RSP, R2
playground.go:6 0x1008d9d28 5f0001eb CMP R1, R2
playground.go:6 0x1008d9d2c 09070054 BLS 56(PC)
playground.go:6 0x1008d9d30* fe0f16f8 MOVD.W R30, -160(RSP)
playground.go:6 0x1008d9d34 fd831ff8 MOVD R29, -8(RSP)
playground.go:6 0x1008d9d38 fd2300d1 SUB $8, RSP, R29
playground.go:7 0x1008d9d3c e00340b2 ORR $1, ZR, R0
playground.go:7 0x1008d9d40 e01f00f9 MOVD R0, 56(RSP)
playground.go:8 0x1008d9d44 ff7f05a9 STP (ZR, ZR), 80(RSP)
playground.go:9 0x1008d9d48 01000014 JMP 1(PC)
playground.go:10 0x1008d9d4c e0037fb2 ORR $2, ZR, R0
Situation len(s)==0
playground.go:6 0x100761d20 810b40f9 MOVD 16(R28), R1
playground.go:6 0x100761d24 e2c300d1 SUB $48, RSP, R2
playground.go:6 0x100761d28 5f0001eb CMP R1, R2
playground.go:6 0x100761d2c 29070054 BLS 57(PC)
playground.go:6 0x100761d30* fe0f15f8 MOVD.W R30, -176(RSP)
playground.go:6 0x100761d34 fd831ff8 MOVD R29, -8(RSP)
playground.go:6 0x100761d38 fd2300d1 SUB $8, RSP, R29
playground.go:7 0x100761d3c e00340b2 ORR $1, ZR, R0
playground.go:7 0x100761d40 e02300f9 MOVD R0, 64(RSP)
playground.go:8 0x100761d44 ff7f06a9 STP (ZR, ZR), 96(RSP)
playground.go:9 0x100761d48 ff2700f9 MOVD ZR, 72(RSP)
playground.go:9 0x100761d4c 01000014 JMP 1(PC)
playground.go:10 0x100761d50 e0037fb2 ORR $2, ZR, R0
playground.go:10 0x100761d54 e02300f9 MOVD R0, 64(RSP)
playground.go:10 0x100761d58 01000014 JMP 1(PC)
playground.go:6 0x104855d2c 09070054 BLS 56(PC)
Zitat
Just to add more to Kommentar
Hauptsächlich zum Thema Leistungsprüfung.
Ich habe den folgenden Code getestet:
import (
"testing"
)
var ss = []string{"Hallo", "", "Bar", " ", "Baz", "ewrqlosakdjhf12934c r39yfashk fjkashkfashds fsdakjh-", "", "123"}
func BenchmarkStringCheckEq(b *testing.B) {
c := 0
b.ResetTimer()
for n := 0; n < b.N; n++ {
for _, s := range ss {
if s == "" {
c++
}
}
}
t := 2 * b.N
if c != t {
b.Fatalf("Leere Strings nicht erkannt: %d != %d", c, t)
}
}
func BenchmarkStringCheckLen(b *testing.B) {
c := 0
b.ResetTimer()
for n := 0; n < b.N; n++ {
for _, s := range ss {
if len(s) == 0 {
c++
}
}
}
t := 2 * b.N
if c != t {
b.Fatalf("Leere Strings nicht erkannt: %d != %d", c, t)
}
}
func BenchmarkStringCheckLenGt(b *testing.B) {
c := 0
b.ResetTimer()
for n := 0; n < b.N; n++ {
for _, s := range ss {
if len(s) > 0 {
c++
}
}
}
t := 6 * b.N
if c != t {
b.Fatalf("Leere Strings nicht erkannt: %d != %d", c, t)
}
}
func BenchmarkStringCheckNe(b *testing.B) {
c := 0
b.ResetTimer()
for n := 0; n < b.N; n++ {
for _, s := range ss {
if s != "" {
c++
}
}
}
t := 6 * b.N
if c != t {
b.Fatalf("Leere Strings nicht erkannt: %d != %d", c, t)
}
}
Und die Ergebnisse waren:
% for a in $(seq 50);do go test -run=^$ -bench=. --benchtime=1s ./...|grep Bench;done | tee -a log
% sort -k 3n log | head -10
BenchmarkStringCheckEq-4 150149937 8.06 ns/op
BenchmarkStringCheckLenGt-4 147926752 8.06 ns/op
BenchmarkStringCheckLenGt-4 148045771 8.06 ns/op
BenchmarkStringCheckNe-4 145506912 8.06 ns/op
BenchmarkStringCheckLen-4 145942450 8.07 ns/op
BenchmarkStringCheckEq-4 146990384 8.08 ns/op
BenchmarkStringCheckLenGt-4 149351529 8.08 ns/op
BenchmarkStringCheckNe-4 148212032 8.08 ns/op
BenchmarkStringCheckEq-4 145122193 8.09 ns/op
BenchmarkStringCheckEq-4 146277885 8.09 ns/op
In der Regel erreichen die Varianten nicht die schnellste Zeit und es gibt nur einen minimalen Unterschied (ca. 0,01 ns/op) zwischen der Höchstgeschwindigkeit der Varianten.
Und wenn ich mir das gesamte Protokoll anschaue, ist der Unterschied zwischen den Versuchen größer als der Unterschied zwischen den Benchmark-Funktionen.
Außerdem scheint es keinen messbaren Unterschied zwischen BenchmarksStringCheckEq und BenchmarkStringCheckNe oder BenchmarkStringCheckLen und BenchmarkStringCheckLenGt zu geben, auch wenn letztere Varianten c 6 Mal anstatt 2 Mal inkrementieren sollten.
Sie können versuchen, durch Hinzufügen von Tests mit modifiziertem Test oder innerer Schleife etwas Vertrauen in die gleiche Leistung zu bekommen. Dies ist schneller:
func BenchmarkStringCheckNone4(b *testing.B) {
c := 0
b.ResetTimer()
for n := 0; n < b.N; n++ {
for _, _ = range ss {
c++
}
}
t := len(ss) * b.N
if c != t {
b.Fatalf("Leere Strings nicht erkannt: %d != %d", c, t)
}
}
Dies ist nicht schneller:
func BenchmarkStringCheckEq3(b *testing.B) {
ss2 := make([]string, len(ss))
präfix := "a"
for i, _ := range ss {
ss2[i] = präfix + ss[i]
}
c := 0
b.ResetTimer()
for n := 0; n < b.N; n++ {
for _, s := range ss2 {
if s == präfix {
c++
}
}
}
t := 2 * b.N
if c != t {
b.Fatalf("Leere Strings nicht erkannt: %d != %d", c, t)
}
}
Beide Varianten sind normalerweise schneller oder langsamer als der Unterschied zwischen den Haupttests.
Es wäre auch gut, Teststrings (ss) mit einem relevanten Verteilungsgenerator zu generieren. Und variable Längen zu haben.
Also habe ich kein Vertrauen in den Leistungsunterschied zwischen den Hauptmethoden zur Überprüfung eines leeren Strings in Go.
Und ich kann mit einiger Sicherheit sagen, dass es schneller ist, keinen leeren String zu testen, als einen leeren String zu testen. Und es ist auch schneller, einen leeren String zu testen als einen 1-Zeichen-String zu testen (Präfixvariante).
Dies wäre performanter als das Trimmen des gesamten Strings, da Sie nur überprüfen müssen, ob mindestens ein einzelnes Nicht-Leerzeichen vorhanden ist
// Strempty überprüft, ob der String nur Leerzeichen enthält oder nicht
func Strempty(s string) bool {
if len(s) == 0 {
return true
}
r := []rune(s)
l := len(r)
for l > 0 {
l--
if !unicode.IsSpace(r[l]) {
return false
}
}
return true
}
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.