Która metoda jest najlepsza (bardziej idomatyczna) do testowania niepustych ciągów (w Go)?
if len(mystring) > 0 { }
Lub:
if mystring != "" { }
Albo coś innego?
Oba style są używane w standardowych bibliotekach Go.
if len(s) > 0 { ... }
można znaleźć w strconv
pakiecie: http://golang.org/src/pkg/strconv/atoi.go
if s != "" { ... }
można znaleźć w encoding/json
pakiecie: http://golang.org/src/pkg/encoding/json/encode.go
Oba są idiomatyczne i wystarczająco jasne. Jest to bardziej kwestia osobistego gustu i przejrzystości.
Russ Cox pisze w wątku golang-nuts :
Ten, który wyjaśnia kod.
Jeśli mam spojrzeć na element x, zwykle piszę
len (s)> x, nawet dla x == 0, ale jeśli mnie to obchodzi
„czy to ten konkretny ciąg„ mam tendencję do pisania s == ””.Można założyć, że dojrzały kompilator skompiluje
len (s) == 0 is s == "" do tego samego, wydajnego kodu.
...Wyczyść kod.
Jak wskazano w odpowiedzi Timmmm , kompilator Go generuje identyczny kod w obu przypadkach.
if mystring != "" { }
jest to najlepszy, preferowany i idiomatyczny sposób DZISIAJ. Powodem, dla którego standardowa biblioteka zawiera inaczej, jest to, że została napisana przed 2010 r., Kiedylen(mystring) == 0
optymalizacja miała sens.len
do sprawdzania pustych / niepustych ciągów. Tak jak to zrobił Brad Fitzpatrick. Obawiam się, że wciąż jest to kwestia gustu i jasności;)len(v) > 0
w h2_bundle.go (linia 2702). Uważam, że nie jest automatycznie wyświetlany, ponieważ jest generowany z golang.org/x/net/http2.To wydaje się być przedwczesną mikrooptymalizacją. Kompilator może generować ten sam kod dla obu przypadków lub przynajmniej dla tych dwóch
i
ponieważ semantyka jest wyraźnie równa.
źródło
Sprawdzanie długości jest dobrą odpowiedzią, ale można również uwzględnić „pusty” ciąg znaków, który jest również tylko białymi spacjami. Nie „technicznie” pusty, ale jeśli chcesz sprawdzić:
źródło
TrimSpace
przydzieli i skopiuje nowy ciąg z oryginalnego ciągu, więc to podejście wprowadzi nieefektywności na dużą skalę.s
ciąg typus[0:i]
zwraca nową kopię. Ciągi są niezmienne w Go, więc czy trzeba tutaj utworzyć kopię?strings.TrimSpace( s )
nie spowoduje przydzielenia nowego ciągu i kopiowania znaków, jeśli ciąg nie wymaga przycinania, ale jeśli ciąg wymaga przycinania, zostanie wywołana dodatkowa kopia (bez znaków spacji).gocritic
Linter sugeruje użyciestrings.TrimSpace(str) == ""
zamiast czeku długości.Zakładając, że należy usunąć puste spacje oraz wszystkie wiodące i końcowe białe spacje:
Ponieważ :
len("") // is 0
len(" ") // one empty space is 1
len(" ") // two empty spaces is 2
źródło
< 1
+1Na razie kompilator Go generuje identyczny kod w obu przypadkach, więc jest to kwestia gustu. GCCGo generuje inny kod, ale prawie nikt go nie używa, więc nie martwię się o to.
https://godbolt.org/z/fib1x1
źródło
Użycie funkcji takiej jak ta poniżej byłoby czystsze i mniej podatne na błędy:
źródło
Aby dodać więcej do komentarza
Głównie o tym, jak przeprowadzić testy wydajności.
Testowałem przy użyciu następującego kodu:
I wyniki były:
Skutecznie warianty zwykle nie osiągają najszybszego czasu i istnieje tylko minimalna różnica (około 0,01ns / operacja) między wariantem prędkości maksymalnej.
A jeśli zajrzę do pełnego dziennika, różnica między próbami jest większa niż różnica między funkcjami testu porównawczego.
Nie wydaje się również, aby istniała jakakolwiek mierzalna różnica między BenchmarkStringCheckEq i BenchmarkStringCheckNe lub BenchmarkStringCheckLen i BenchmarkStringCheckLenGt, nawet jeśli te ostatnie warianty powinny zawierać c 6 razy zamiast 2 razy.
Możesz spróbować uzyskać pewność co do równej wydajności, dodając testy ze zmodyfikowanym testem lub pętlą wewnętrzną. Jest to szybsze:
To nie jest szybsze:
Oba warianty są zwykle szybsze lub wolniejsze niż różnica między głównymi testami.
Dobrze byłoby również wygenerować łańcuchy testowe (ss) przy użyciu generatora łańcuchów o odpowiednim rozkładzie. I mają też różne długości.
Więc nie mam żadnej pewności co do różnicy wydajności między głównymi metodami testowania pustego łańcucha w ruchu.
Mogę stwierdzić z pewną pewnością, że szybciej nie testować pustego łańcucha niż testować pusty łańcuch. A także szybsze jest testowanie pustego łańcucha niż testowanie 1 łańcucha znaków (wariant prefiksu).
źródło
Zgodnie z oficjalnymi wytycznymi iz punktu widzenia wydajności wydają się one równoważne ( odpowiedź ANisus ), s! = "" Byłoby lepsze ze względu na przewagę syntaktyczną. s! = "" zakończy się niepowodzeniem w czasie kompilacji, jeśli zmienna nie jest łańcuchem, a len (s) == 0 przejdzie dla kilku innych typów danych.
źródło
len()
wymaga tylko trochę więcej pracy. JEDNAK, jedną rzeczą, którą robiliśmy w C, było przeniesienie lewej strony na aconst
lub umieszczenie ciągu statycznego po lewej stronie operatora, aby zapobiec s == "" zamienianiu się w s = "", co w składni C jest dopuszczalne. .. i prawdopodobnie również Golanga. (patrz przedłużony, jeśli)Byłoby to bardziej wydajne niż przycinanie całego łańcucha, ponieważ wystarczy sprawdzić przynajmniej jeden istniejący znak spacji
źródło
Myślę, że najlepszym sposobem jest porównanie z pustym ciągiem
BenchmarkStringCheck1 sprawdza pusty ciąg znaków
BenchmarkStringCheck2 sprawdza z długością zerową
Sprawdzam za pomocą sprawdzania pustych i niepustych ciągów. Widać, że sprawdzanie pustym ciągiem jest szybsze.
Kod
źródło