답변:
두 가지 스타일 모두 Go의 표준 라이브러리에서 사용됩니다.
if len(s) > 0 { ... }
strconv
패키지 에서 찾을 수 있습니다 : http://golang.org/src/pkg/strconv/atoi.go
if s != "" { ... }
encoding/json
패키지 에서 찾을 수 있습니다 : http://golang.org/src/pkg/encoding/json/encode.go
둘 다 관용적이고 충분히 명확합니다. 그것은 개인적인 취향과 명확성에 관한 문제입니다.
Russ Cox는 golang-nuts 스레드에 씁니다 .
코드를 명확하게하는 것
요소 x를 보려고하면 일반적으로
x == 0 인 경우에도 len (s)> x를 쓰지만
"이 특정 문자열"에 관심 이 있다면 s == ""를 쓰는 경향이 있습니다.성숙한 컴파일러가
len (s) == 0 및 s == ""를 동일한 효율적인 코드로 컴파일한다고 가정하는 것이 합리적 입니다.
...코드를 명확하게하십시오.
Timmmm의 답변 에서 지적했듯이 Go 컴파일러는 두 경우 모두 동일한 코드를 생성합니다.
len(v) > 0
에서 언급했습니다 . golang.org/x/net/http2에서 생성되므로 자동으로 표시되지 않습니다.
이것은 조기 미세 최적화로 보입니다. 컴파일러는 두 경우 모두 또는 적어도 두 가지 모두에 대해 동일한 코드를 자유롭게 생성 할 수 있습니다
if len(s) != 0 { ... }
과
if s != "" { ... }
의미론이 분명히 동일하기 때문입니다.
길이를 확인하는 것이 좋은 대답이지만 공백 만있는 "빈"문자열을 설명 할 수도 있습니다. "기술적으로"비어 있지는 않지만 확인해야 할 경우 :
package main
import (
"fmt"
"strings"
)
func main() {
stringOne := "merpflakes"
stringTwo := " "
stringThree := ""
if len(strings.TrimSpace(stringOne)) == 0 {
fmt.Println("String is empty!")
}
if len(strings.TrimSpace(stringTwo)) == 0 {
fmt.Println("String two is empty!")
}
if len(stringTwo) == 0 {
fmt.Println("String two is still empty!")
}
if len(strings.TrimSpace(stringThree)) == 0 {
fmt.Println("String three is empty!")
}
}
TrimSpace
원래 문자열에서 새 문자열을 할당하고 복사하므로이 방법으로 인해 비 효율성이 발생합니다.
s
문자열 유형 인 경우에만 s[0:i]
새 사본을 리턴하는 경우에만 적용됩니다 . Go에서는 문자열을 변경할 수 없으므로 여기에서 복사본을 만들어야합니까?
strings.TrimSpace( s )
문자열을 다듬을 필요가없는 경우 새 문자열 할당 및 문자 복사를 유발하지 않지만 문자열을 다듬어야하는 경우 추가 공백 (공백 문자없이)이 호출됩니다.
gocritic
린터 사용하여 제안 strings.TrimSpace(str) == ""
대신 길이 검사의.
빈 공간과 모든 선행 및 후행 공백을 제거해야한다고 가정합니다.
import "strings"
if len(strings.TrimSpace(s)) == 0 { ... }
때문에 :
len("") // is 0
len(" ") // one empty space is 1
len(" ") // two empty spaces is 2
< 1
+1로 만드는 것입니다
현재 Go 컴파일러는 두 경우 모두 동일한 코드를 생성하므로 맛의 문제입니다. GCCGo는 다른 코드를 생성하지만 간신히 누군가가 사용하므로 걱정하지 않습니다.
아래와 같은 기능을 사용하는 것이 더 깨끗하고 오류가 덜 발생합니다.
func empty(s string) bool {
return len(strings.TrimSpace(s)) == 0
}
의견을 더 추가하려면
주로 성능 테스트를 수행하는 방법에 대해 설명합니다.
다음 코드로 테스트했습니다.
import (
"testing"
)
var ss = []string{"Hello", "", "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("did not catch empty strings: %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("did not catch empty strings: %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("did not catch empty strings: %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("did not catch empty strings: %d != %d", c, t)
}
}
결과는 다음과 같습니다.
% 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
효과적으로 변형은 일반적으로 가장 빠른 시간에 도달하지 않으며 변형 최고 속도간에 최소한의 차이 (약 0.01ns / op) 만 있습니다.
그리고 전체 로그를 보면 시도 간의 차이가 벤치 마크 함수의 차이보다 큽니다.
또한 후자의 변형이 2 번이 아닌 6 번 증가해야하더라도 BenchmarkStringCheckEq와 BenchmarkStringCheckNe 또는 BenchmarkStringCheckLen 및 BenchmarkStringCheckLenGt간에 측정 가능한 차이가없는 것으로 보입니다.
수정 된 테스트 또는 내부 루프로 테스트를 추가하여 동일한 성능에 대한 확신을 얻을 수 있습니다. 이것은 더 빠릅니다.
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("did not catch empty strings: %d != %d", c, t)
}
}
이것은 더 빠르지 않습니다.
func BenchmarkStringCheckEq3(b *testing.B) {
ss2 := make([]string, len(ss))
prefix := "a"
for i, _ := range ss {
ss2[i] = prefix + ss[i]
}
c := 0
b.ResetTimer()
for n := 0; n < b.N; n++ {
for _, s := range ss2 {
if s == prefix {
c++
}
}
}
t := 2 * b.N
if c != t {
b.Fatalf("did not catch empty strings: %d != %d", c, t)
}
}
두 변종 모두 일반적으로 주 테스트의 차이보다 빠르거나 느립니다.
관련 분포가있는 문자열 생성기를 사용하여 테스트 문자열 (ss)을 생성하는 것도 좋습니다. 길이도 다양합니다.
따라서 빈 문자열을 테스트하는 주요 방법 사이의 성능 차이에 대해 확신 할 수 없습니다.
그리고 나는 확신을 가지고 말할 수 있습니다. 빈 문자열을 테스트하는 것보다 빈 문자열을 테스트하지 않는 것이 더 빠릅니다. 또한 1 개의 문자열 (접두사 변형)을 테스트하는 것보다 빈 문자열을 테스트하는 것이 더 빠릅니다.
공식적인 지침과 성능 관점에서 볼 때 그것들은 동등한 것으로 보이며 ( ANisus answer ), 구문 상 이점 때문에 s! = ""가 더 좋습니다. s! = ""는 변수가 문자열이 아닌 경우 컴파일 타임에 실패하지만 len (s) == 0은 다른 여러 데이터 유형에 전달됩니다.
len()
약간의 추가 작업이 필요합니다. 그러나 C에서 사용했던 한 가지 일은 왼쪽을 a로 캐스트 const
하거나 연산자의 왼쪽에 정적 문자열을 넣어 s == ""가 s = ""가되는 것을 방지하기 위해 C 구문에서 허용됩니다. .. 그리고 아마도 golang도. (확장 된 경우 참조)
공백이 아닌 문자가 하나 이상 있는지 확인하면되므로 전체 문자열을 자르는 것보다 성능이 뛰어납니다.
// Strempty checks whether string contains only whitespace or not
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
}
가장 좋은 방법은 빈 문자열과 비교하는 것입니다.
BenchmarkStringCheck1이 빈 문자열로 확인 중입니다.
BenchmarkStringCheck2는 len zero로 확인 중입니다.
비어 있고 비어 있지 않은 문자열 검사로 확인합니다. 빈 문자열로 확인하는 것이 더 빠르다는 것을 알 수 있습니다.
BenchmarkStringCheck1-4 2000000000 0.29 ns/op 0 B/op 0 allocs/op
BenchmarkStringCheck1-4 2000000000 0.30 ns/op 0 B/op 0 allocs/op
BenchmarkStringCheck2-4 2000000000 0.30 ns/op 0 B/op 0 allocs/op
BenchmarkStringCheck2-4 2000000000 0.31 ns/op 0 B/op 0 allocs/op
암호
func BenchmarkStringCheck1(b *testing.B) {
s := "Hello"
b.ResetTimer()
for n := 0; n < b.N; n++ {
if s == "" {
}
}
}
func BenchmarkStringCheck2(b *testing.B) {
s := "Hello"
b.ResetTimer()
for n := 0; n < b.N; n++ {
if len(s) == 0 {
}
}
}
if mystring != "" { }
최고에, 선호와 관용적 방법 오늘이다. 표준 라이브러리에 다른 이유가 포함되어있는 이유는 2010 년 이전에len(mystring) == 0
최적화가 적합하게 작성 되었기 때문 입니다.