string 在 Go 中测试空字符串的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18594330/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the best way to test for an empty string in Go?
提问by Richard
Which method is best (more idomatic) for testing non-empty strings (in Go)?
哪种方法最适合(更惯用)测试非空字符串(在 Go 中)?
if len(mystring) > 0 { }
Or:
或者:
if mystring != "" { }
Or something else?
或者是其他东西?
回答by ANisus
Both styles are used within the Go's standard libraries.
这两种风格都在 Go 的标准库中使用。
if len(s) > 0 { ... }
can be found in the strconv
package: http://golang.org/src/pkg/strconv/atoi.go
可以在strconv
包中找到:http: //golang.org/src/pkg/strconv/atoi.go
if s != "" { ... }
can be found in the encoding/json
package: http://golang.org/src/pkg/encoding/json/encode.go
可以在encoding/json
包中找到:http: //golang.org/src/pkg/encoding/json/encode.go
Both are idiomatic and are clear enough. It is more a matter of personal taste and about clarity.
两者都是惯用的,并且足够清楚。这更多是个人品味和清晰度的问题。
Russ Cox writes in a golang-nuts thread:
Russ Cox 在golang-nuts 线程中写道:
The one that makes the code clear.
If I'm about to look at element x I typically write
len(s) > x, even for x == 0, but if I care about
"is it this specific string" I tend to write s == "".It's reasonable to assume that a mature compiler will compile
len(s) == 0 and s == "" into the same, efficient code.
...Make the code clear.
使代码清晰的那个。
如果我要查看元素 x,我通常会写
len(s) > x,即使 x == 0,但如果我关心
“它是这个特定的字符串吗”,我倾向于写 s == ""。可以合理地假设成熟的编译器会将
len(s) == 0 和 s == ""编译成相同的高效代码。
...让代码清晰。
As pointed out in Timmmm's answer, the Go compiler does generate identical code in both cases.
正如Timmmm 的回答中所指出的,Go 编译器在两种情况下都会生成相同的代码。
回答by zzzz
This seems to be premature microoptimization. The compiler is free to produce the same code for both cases or at least for these two
这似乎是过早的微优化。编译器可以自由地为这两种情况或至少为这两种情况生成相同的代码
if len(s) != 0 { ... }
and
和
if s != "" { ... }
because the semantics is clearly equal.
因为语义显然是平等的。
回答by Wilhelm Murdoch
Checking for length is a good answer, but you could also account for an "empty" string that is also only whitespace. Not "technically" empty, but if you care to check:
检查长度是一个很好的答案,但您也可以考虑一个也只是空格的“空”字符串。不是“技术上”空的,但如果你想检查:
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!")
}
}
回答by Edwinner
Assuming that empty spaces and all leading and trailing white spaces should be removed:
假设应删除空格和所有前导和尾随空格:
import "strings"
if len(strings.TrimSpace(s)) == 0 { ... }
Because :len("") // is 0
len(" ") // one empty space is 1
len(" ") // two empty spaces is 2
因为 :len("") // is 0
len(" ") // one empty space is 1
len(" ") // two empty spaces is 2
回答by Timmmm
As of now, the Go compiler generates identical code in both cases, so it is a matter of taste. GCCGo does generate different code, but barely anyone uses it so I wouldn't worry about that.
截至目前,Go 编译器在两种情况下都会生成相同的代码,因此这是一个品味问题。GCCGo 确实生成了不同的代码,但几乎没有人使用它,所以我不会担心。
回答by Yannis Sermetziadis
It would be cleaner and less error-prone to use a function like the one below:
使用像下面这样的函数会更干净,更不容易出错:
func empty(s string) bool {
return len(strings.TrimSpace(s)) == 0
}
回答by Markus Linnala
Just to add more to comment
只是为了添加更多评论
Mainly about how to do performance testing.
主要是关于如何做性能测试。
I did testing with following code:
我使用以下代码进行了测试:
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)
}
}
And results were:
结果是:
% 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
Effectively variants usually do not reach fastest time and there is only minimal difference (about 0.01ns/op) between variant top speed.
有效的变体通常不会达到最快的时间,并且变体的最高速度之间只有很小的差异(大约 0.01ns/op)。
And if I look full log, difference between tries is greater than difference between benchmark functions.
如果我查看完整日志,尝试之间的差异大于基准函数之间的差异。
Also there does not seem to be any measurable difference between BenchmarkStringCheckEq and BenchmarkStringCheckNe or BenchmarkStringCheckLen and BenchmarkStringCheckLenGt even if latter variants should inc c 6 times instead of 2 times.
此外,BenchmarkStringCheckEq 和 BenchmarkStringCheckNe 或 BenchmarkStringCheckLen 和 BenchmarkStringCheckLenGt 之间似乎没有任何可测量的差异,即使后者的变体应该包括 6 次而不是 2 次。
You can try to get some confidence about equal performance by adding tests with modified test or inner loop. This is faster:
您可以尝试通过添加带有修改测试或内部循环的测试来获得对同等性能的信心。这更快:
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)
}
}
This is not faster:
这不是更快:
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)
}
}
Both variants are usually faster or slower than difference between main tests.
这两种变体通常比主要测试之间的差异更快或更慢。
It would also good to generate test strings (ss) using string generator with relevant distribution. And have variable lengths too.
使用具有相关分布的字符串生成器生成测试字符串 (ss) 也很好。并且也有可变长度。
So I don't have any confidence of performance difference between main methods to test empty string in go.
所以我对在 go 中测试空字符串的主要方法之间的性能差异没有任何信心。
And I can state with some confidence, it is faster not to test empty string at all than test empty string. And also it is faster to test empty string than to test 1 char string (prefix variant).
而且我可以自信地说,根本不测试空字符串比测试空字符串要快。而且测试空字符串比测试 1 个字符字符串(前缀变体)更快。
回答by Janis Viksne
As per official guidelines and from performance point of view they appear equivalent (ANisus answer), the s != "" would be better due to a syntactical advantage. s != "" will fail at compile time if the variable is not a string, while len(s) == 0 will pass for several other data types.
根据官方指南,从性能的角度来看,它们看起来是等效的(ANisus 答案),由于语法优势, s != "" 会更好。如果变量不是字符串,s != "" 将在编译时失败,而 len(s) == 0 将通过其他几种数据类型。
回答by Brian Leishman
This would be more performant than trimming the whole string, since you only need to check for at least a single non-space character existing
这将比修剪整个字符串更高效,因为您只需要检查至少存在一个非空格字符
// 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
}
回答by Ketan Parmar
I think the best way is to compare with blank string
我认为最好的方法是与空白字符串进行比较
BenchmarkStringCheck1 is checking with blank string
BenchmarkStringCheck1 正在检查空字符串
BenchmarkStringCheck2 is checking with len zero
BenchmarkStringCheck2 正在检查 len 零
I check with the empty and non-empty string checking. You can see that checking with a blank string is faster.
我检查空和非空字符串检查。您可以看到使用空字符串进行检查会更快。
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
Code
代码
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 {
}
}
}