गो में खाली स्ट्रिंग के लिए परीक्षण करने का सबसे अच्छा तरीका क्या है?


260

गैर-रिक्त तार (गो में) के परीक्षण के लिए कौन सी विधि सबसे अच्छी (अधिक मुहावरेदार) है?

if len(mystring) > 0 { }

या:

if mystring != "" { }

या कुछ और?

जवाबों:


388

दोनों शैलियों का उपयोग गो के मानक पुस्तकालयों के भीतर किया जाता है।

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

दोनों मुहावरेदार हैं और पर्याप्त स्पष्ट हैं। यह व्यक्तिगत स्वाद और स्पष्टता के बारे में अधिक बात है।

रस कॉक्स एक गोल-नट धागा में लिखते हैं :

वह जो कोड को स्पष्ट करता है।
अगर मैं तत्व x को देखने वाला हूं, तो मैं आमतौर पर
len (s)> x, यहां तक ​​कि x == 0 के लिए भी लिखता हूं , लेकिन अगर मुझे
"इस बात की परवाह है " तो यह विशिष्ट स्ट्रिंग है "मैं s ==" लिखना चाहता हूं।

यह मानना ​​उचित है कि एक परिपक्व संकलक
len (s) == 0 और s == "" को एक ही, कुशल कोड में संकलित करेगा ।
...

कोड स्पष्ट करें।

जैसा कि टिम्मम के जवाब में कहा गया है , गो संकलक दोनों मामलों में समान कोड उत्पन्न करता है।


1
मैं इस जवाब से सहमत नहीं हूं। बस if mystring != "" { }सबसे अच्छा, पसंदीदा और मुहावरेदार तरीका TODAY है। कारण मानक पुस्तकालय में अन्यथा शामिल है क्योंकि यह 2010 से पहले लिखा गया था जब len(mystring) == 0अनुकूलन ने समझदारी की।
होनजजडे

12
@honzajde बस अपने बयान को मान्य करने की कोशिश की, लेकिन lenखाली / गैर-खाली तारों की जांच करने के लिए 1 वर्ष से कम पुरानी मानक लाइब्रेरी में कमिट किया गया । इस तरह प्रतिबद्ध ब्रैड Fitzpatrick द्वारा। मुझे डर है कि यह अभी भी स्वाद और स्पष्टता की बात है;)
एनिसस

6
@honzajde ट्रोलिंग नहीं कमिट में 3 लेन कीवर्ड हैं। मैं करने के लिए बात कर रहे थे len(v) > 0में h2_bundle.go (लाइन 2702)। यह स्वचालित रूप से नहीं दिखाया गया है क्योंकि यह golang.org/x/net/http2 से उत्पन्न होता है, मेरा मानना ​​है।
एनिसस

2
यदि यह अंतर में noi है तो यह नया नहीं है। आप सीधे लिंक पोस्ट क्यों नहीं करते? वैसे भी। मेरे लिए पर्याप्त जासूसी का काम ... मैं इसे नहीं देखता।
होनजजडे १६'१

6
@honzajde कोई चिंता नहीं। मुझे लगता है कि अन्य लोग h2_bundle.go फ़ाइल के लिए "लोड अंतर" पर क्लिक करने के बारे में जानेंगे।
ऐनीसस

30

यह समय से पहले microoptimization लगता है। संकलक दोनों मामलों के लिए या कम से कम इन दोनों के लिए समान कोड का उत्पादन करने के लिए स्वतंत्र है

if len(s) != 0 { ... }

तथा

if s != "" { ... }

क्योंकि शब्दार्थ स्पष्ट रूप से समान है।


1
हालांकि, सहमत हैं, यह वास्तव में स्ट्रिंग के कार्यान्वयन पर निर्भर करता है ... यदि स्ट्रिंग्स पास्कल की तरह कार्यान्वित किए जाते हैं तो ओ (1) में लेन निष्पादित किया जाता है और यदि सी की तरह है तो यह ओ (एन) है। या जो भी हो, चूंकि लेन () को पूरा करने के लिए निष्पादित करना है।
रिचर्ड

क्या आपने यह देखने के लिए कोड पीढ़ी पर ध्यान दिया है कि क्या कंपाइलर यह अनुमान लगाता है या आप केवल यह सुझाव दे रहे हैं कि एक कंपाइलर इसे लागू कर सकता है?
माइकल लेबबे जूल

19

लंबाई की जाँच करना एक अच्छा जवाब है, लेकिन आप "खाली" स्ट्रिंग के लिए भी जिम्मेदार हो सकते हैं, जो कि केवल व्हाट्सएप भी है। "तकनीकी रूप से" खाली नहीं है, लेकिन अगर आप जांचना चाहते हैं:

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]एक नई प्रति लौटाता है। स्ट्रिंग्स गो में अपरिवर्तनीय हैं, इसलिए क्या यहां एक प्रति बनाने की आवश्यकता है?
माइकल पेसोल्ड

@MichaelPaesold राइट - strings.TrimSpace( s )यदि स्ट्रिंग को ट्रिमिंग की आवश्यकता नहीं है, तो नए स्ट्रिंग आवंटन और वर्ण प्रतिलिपि का कारण नहीं होगा, लेकिन यदि स्ट्रिंग को ट्रिमिंग की आवश्यकता है, तो अतिरिक्त प्रतिलिपि (बिना व्हाट्सएप वर्ण) को आमंत्रित किया जाएगा।
दाई

1
"तकनीकी रूप से खाली" सवाल है।
रिचर्ड

gocriticलिंटर उपयोग करने का सुझाव strings.TrimSpace(str) == ""लंबाई जांच के बजाय।
y3sh

12

यह मानते हुए कि खाली स्थान और सभी प्रमुख और पीछे वाले सफेद स्थानों को हटा दिया जाना चाहिए:

import "strings"
if len(strings.TrimSpace(s)) == 0 { ... }

इसलिये :
len("") // is 0
len(" ") // one empty space is 1
len(" ") // two empty spaces is 2


2
आपकी यह धारणा क्यों है? आदमी खाली स्ट्रिंग के बारे में स्पष्ट रूप से बताता है। उसी तरह आप बता सकते हैं, यह मानते हुए कि आप एक स्ट्रिंग में केवल एससीआई अक्षर चाहते हैं और फिर एक फ़ंक्शन जोड़ते हैं जो सभी गैर-एससीआई चार्ट को हटा देता है।
साल्वाडोर डाली

1
क्योंकि len (""), len ("") और len ("") जाने में समान बात नहीं है। मैं यह मान रहा था कि वह यह सुनिश्चित करना चाहता था कि एक चर जिसे उसने पहले उनमें से एक के लिए शुरू किया था, वास्तव में अभी भी "तकनीकी रूप से" खाली है।
एडविननर

यह वास्तव में वही है जो मुझे इस पद से चाहिए था। मुझे कम से कम 1 गैर-व्हाट्सएप चरित्र के लिए उपयोगकर्ता इनपुट की आवश्यकता है और यह एक-लाइनर स्पष्ट और संक्षिप्त है। मुझे बस इतना करने की जरूरत है कि अगर हालत < 11 है
Shadoninja

7

अब तक, गो संकलक दोनों मामलों में समान कोड बनाता है, इसलिए यह स्वाद का मामला है। GCCGo अलग कोड उत्पन्न करता है, लेकिन बमुश्किल कोई भी इसका उपयोग करता है इसलिए मुझे इस बारे में चिंता नहीं होगी।

https://godbolt.org/z/fib1x1


1

नीचे दिए गए फ़ंक्शन की तरह उपयोग करने के लिए यह क्लीनर और कम त्रुटि वाला होगा:

func empty(s string) bool {
    return len(strings.TrimSpace(s)) == 0
}

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) होता है।

और अगर मैं पूर्ण लॉग देखता हूं, तो कोशिशों के बीच का अंतर बेंचमार्क कार्यों के बीच अंतर से अधिक है।

इसके अलावा BenchmarkStringCheckEq और BenchmarkStringCheckNe या BenchmarkStringCheckLen और BenchmarkStringCheckLenGt के बीच कोई भी औसत दर्जे का अंतर नहीं लगता है, जबकि बाद वाले वेरिएंट को भी 2 बार के बजाय 6 गुना इंक चाहिए।

आप संशोधित परीक्षण या इनर लूप के साथ परीक्षणों को जोड़कर समान प्रदर्शन के बारे में कुछ आत्मविश्वास प्राप्त करने की कोशिश कर सकते हैं। यह तेज़ है:

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 चर स्ट्रिंग (उपसर्ग संस्करण) का परीक्षण करने की तुलना में खाली स्ट्रिंग का परीक्षण करने के लिए तेज़ है।


0

आधिकारिक दिशानिर्देशों के अनुसार और प्रदर्शन के दृष्टिकोण से वे समतुल्य दिखाई देते हैं ( एनीसस उत्तर ), एस! = "" एक वाक्यविन्यास लाभ के कारण बेहतर होगा। s! = "" संकलन समय पर विफल हो जाएगा यदि चर एक स्ट्रिंग नहीं है, जबकि len (s) == 0 कई अन्य डेटा प्रकारों के लिए पारित होगा।


एक समय था जब मैंने सीपीयू चक्रों की गणना की और कोडांतरक की समीक्षा की कि सी कंपाइलर ने सी और पास्कल स्ट्रिंग्स की संरचना का उत्पादन और गहराई से समझा ... यहां तक ​​कि दुनिया में सभी अनुकूलन के साथ len()बस उस छोटे से अतिरिक्त काम की आवश्यकता है। फिर भी, एक चीज़ जो हम C में करते थे, वह बाईं ओर डाली गई थी constया ऑपरेटर के बाईं ओर स्थिर स्ट्रिंग को रखने के लिए s == "" को s = "" बनने से रोकने के लिए थी, जो C वाक्यविन्यास में स्वीकार्य है। .. और शायद गोलंग भी। (अगर विस्तारित देखें)
रिचर्ड

-1

यह पूरे स्ट्रिंग को ट्रिम करने की तुलना में अधिक प्रदर्शनकारी होगा, क्योंकि आपको केवल कम से कम एक सिंगल-स्पेस चरित्र की जांच करने की आवश्यकता है

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

3
@ रीचर्ड जो हो सकता है, लेकिन जब गॉग्लिंग "अगर चेक खाली है या स्ट्रिंग समान है" के लिए Googling, तो यह एकमात्र सवाल है जो सामने आता है, इसलिए उन लोगों के लिए यह उनके लिए है, जो एक अभूतपूर्व बात नहीं है स्टैक एक्सचेंज
ब्रायन लीशमैन

-1

मुझे लगता है कि खाली स्ट्रिंग के साथ तुलना करने का सबसे अच्छा तरीका है

BenchmarkStringCheck1 रिक्त स्ट्रिंग के साथ जाँच कर रहा है

BenchmarkStringCheck2 लेन ज़ेन के साथ जाँच कर रहा है

मैं खाली और गैर-रिक्त स्ट्रिंग जाँच के साथ जाँच करता हूँ। आप देख सकते हैं कि रिक्त स्ट्रिंग के साथ जाँच तेज है।

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 {

        }
    }
}

5
मुझे लगता है कि यह सबूत कुछ भी नहीं है। चूँकि आपका कंप्यूटर परीक्षण करते समय अन्य काम करता है और यह कहना छोटा होता है कि एक दूसरे से तेज़ है। यह संकेत दे सकता है कि दोनों फ़ंक्शन समान कॉल के लिए संकलित किए गए थे।
एसआर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.