इंटरफेस के स्लाइस परिवर्तित प्रकार


194

मुझे उत्सुकता है कि गो क्यों नहीं []Tहै []interface{}जब यह अंतर्निहित रूप से परिवर्तित Tहो जाएगा interface{}। क्या इस रूपांतरण के बारे में कुछ गैर-तुच्छ है जो मुझे याद आ रही है?

उदाहरण:

func foo([]interface{}) { /* do something */ }

func main() {
    var a []string = []string{"hello", "world"}
    foo(a)
}

go build शिकायत

फ़ंक्शन तर्क में टाइप [] इंटरफ़ेस {} के रूप में (टाइप [] स्ट्रिंग) का उपयोग नहीं किया जा सकता है

और अगर मैं इसे स्पष्ट रूप से करने की कोशिश करता हूं, तो एक ही बात: b := []interface{}(a)शिकायत करता है

एक प्रकार ([] स्ट्रिंग) को टाइप करने के लिए [] इंटरफ़ेस {} में नहीं बदल सकता

इसलिए हर बार मुझे इस रूपांतरण को करने की जरूरत है (जो बहुत ऊपर आता है), मैं कुछ इस तरह कर रहा हूं:

b = make([]interface{}, len(a), len(a))
for i := range a {
    b[i] = a[i]
}

क्या ऐसा करने का एक बेहतर तरीका है, या मानक पुस्तकालय इन रूपांतरणों की सहायता के लिए कार्य करता है? हर बार जब मैं एक फ़ंक्शन को कॉल करना चाहता हूं, तो कोड की 4 अतिरिक्त पंक्तियों को लिखने के लिए यह मूर्खतापूर्ण लगता है जो कि उदाहरण के लिए इन्ट्स या स्ट्रिंग्स की सूची ले सकता है।


इसलिए आप "स्पष्ट रूप से कन्वर्ट [] T से [] इंटरफ़ेस {}" को परिभाषित करते हैं, जिसका अर्थ है "एक नया टुकड़ा आवंटित करना और सभी तत्वों को कॉपी करना"। यह असंगत है कि "स्पष्ट रूप से टी को इंटरफ़ेस {}" में किस रूप में परिवर्तित किया जाता है, जो कि अधिक सामान्य स्थैतिक प्रकार के समान मूल्य का एक दृश्य है; कुछ भी कॉपी नहीं किया गया है; और यदि आप इसे टाइप टी पर वापस टाइप करते हैं, तो आपको फिर भी वही चीज़ वापस मिल जाएगी।
newacct

1
इसे कैसे लागू किया जाएगा, इसके बारे में बहुत विस्तार से नहीं सोच रहा था, बस एक उच्च स्तर पर यह आसानी से जेनेरिक प्रकार न होने के लिए वर्कअराउंड के रूप में एक पूरी सूची को दूसरे प्रकार में बदलने में सक्षम होने के लिए सुविधाजनक होगा।
danny

जवाबों:


215

गो में, एक सामान्य नियम है कि सिंटैक्स को जटिल / महंगा संचालन को छिपाना नहीं चाहिए। परिवर्तित करनाstring करना interface{}O (1) समय में किया जाता है। एक []stringसे एक interface{}में परिवर्तित करना O (1) समय में भी किया जाता है क्योंकि एक टुकड़ा अभी भी एक मूल्य है। हालाँकि, a []stringको []interface{}O (n) समय में बदलना क्योंकि स्लाइस के प्रत्येक तत्व को a में बदलना चाहिए interface{}

इस नियम का एक अपवाद स्ट्रिंग्स को परिवर्तित करना है। रूपांतरणों stringको a []byteया a से परिवर्तित करते समय []rune, Go O (n) कार्य करता है, भले ही रूपांतरण "वाक्यविन्यास" हो।

कोई मानक लाइब्रेरी फ़ंक्शन नहीं है जो आपके लिए यह रूपांतरण करेगा। आप एक को प्रतिबिंबित कर सकते हैं, लेकिन यह तीन लाइन विकल्प की तुलना में धीमा होगा।

प्रतिबिंब के साथ उदाहरण:

func InterfaceSlice(slice interface{}) []interface{} {
    s := reflect.ValueOf(slice)
    if s.Kind() != reflect.Slice {
        panic("InterfaceSlice() given a non-slice type")
    }

    ret := make([]interface{}, s.Len())

    for i:=0; i<s.Len(); i++ {
        ret[i] = s.Index(i).Interface()
    }

    return ret
}

हालांकि आपका सबसे अच्छा विकल्प यह है कि आप अपने प्रश्न में दिए गए कोड की पंक्तियों का उपयोग करें:

b := make([]interface{}, len(a))
for i := range a {
    b[i] = a[i]
}

3
यह धीमा हो सकता है, लेकिन यह किसी भी प्रकार के स्लाइस के साथ
उदारता से

यह पूरा उत्तर stw पर लागू होता है map
रिकी

यह भी लागू होता है channels
जस्टिन

स्पष्ट स्पष्टीकरण के लिए धन्यवाद, यदि संभव हो तो आप रेफरी जोड़ सकते हैं। के लिए Converting a []string to an interface{} is also done in O(1) time?
मयूर

56

जो चीज़ आपको याद आ रही है वह है Tऔर interface{}जो Tस्मृति में विभिन्न अभ्यावेदन का मूल्य रखती है ताकि तुच्छ रूप से रूपांतरित न हो सके।

प्रकार Tका एक चर स्मृति में सिर्फ इसका मूल्य है। कोई संबद्ध प्रकार की जानकारी नहीं है (गो में प्रत्येक चर का एक ही प्रकार ज्ञात होता है जो संकलन समय पर नहीं होता है)। इसे इस तरह से मेमोरी में दर्शाया जाता है:

  • मूल्य

एक interface{}पकड़े प्रकार का एक चर Tइस तरह स्मृति में प्रतिनिधित्व किया है

  • टाइप करने का सूचक T
  • मूल्य

इसलिए अपने मूल प्रश्न पर वापस आएँ: क्यों न जाने के लिए संक्षेप में परिवर्तित []Tहो []interface{}?

परिवर्तित []Tकरने []interface{}के लिए interface {}मूल्यों का एक नया टुकड़ा बनाना शामिल होगा जो कि एक गैर-तुच्छ ऑपरेशन है क्योंकि इन-मेमोरी लेआउट पूरी तरह से अलग है।


10
यह जानकारीपूर्ण और अच्छी तरह से लिखा (+1) है, लेकिन आप उनके प्रश्न के दूसरे भाग को संबोधित नहीं कर रहे हैं: "क्या ऐसा करने का एक बेहतर तरीका है ..." (-1)।
वेबर 2

13

यहाँ आधिकारिक विवरण है: https://github.com/golang/go/wiki/InterfaceSlice

var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
    interfaceSlice[i] = d
}

अच्छी जानकारी लेकिन यह एक आधिकारिक स्पष्टीकरण नहीं है। यह एक विकि है जहाँ हर कोई संपादन कर सकता है।
इनक गमुस

मुझे []interfaceउस प्रकार से कैसे परिवर्तित करना चाहिए जिसकी मुझे उम्मीद है []map[string]interface{}?
लुईस चान

8

interface{}इसके बजाय कोशिश करें । टुकड़ा के रूप में वापस लाने के लिए, प्रयास करें

func foo(bar interface{}) {
    s := bar.([]string)
    // ...
}

3
यह अगले प्रश्न के लिए भीख माँगता है: कैसे ओपी को फिर से इसे पुनरावृत्त करना चाहिए barताकि इसे "किसी भी प्रकार का एक टुकड़ा" के रूप में व्याख्या की जा सके? ध्यान दें कि उसका थ्री-लाइनर अन्य ठोस प्रकार का एक []interface{}, नहीं []stringया टुकड़ा बनाता है ।
कोस्टिक्स

13
-1: यह केवल तभी काम करता है यदि बार [] स्ट्रिंग है, जिस स्थिति में, आप भी लिख सकते हैं:func foo(bar []string) { /* ... */ }
weberc2

2
एक प्रकार के स्विच का उपयोग करें, या स्वीकृत उत्तर में प्रतिबिंब का उपयोग करें।
डस्किनर

ओपी को किसी भी तरह से रन टाइम में अपने प्रकार का पता लगाना होगा। नॉन स्लाइस का उपयोग interface{}करने से कंपाइलर को शिकायत नहीं होगी जब वह एक तर्क को पारित कर देगा foo(a)। वह या तो प्रतिबिंबित या टाइपिंग स्विचिंग ( golang.org/doc/effective_go.html#type_switch ) का उपयोग कर सकता है foo
कैसियोहग

2

interface{}किसी भी प्रकार में परिवर्तित करें ।

वाक्य - विन्यास:

result := interface.(datatype)

उदाहरण:

var employee interface{} = []string{"Jhon", "Arya"}
result := employee.([]string)   //result type is []string.

2
क्या आपको इसका यकीन है? मुझे नहीं लगता कि यह मान्य है। आप इसे देखने जा रहे हैं: invalid type assertion: potato.([]string) (non-interface type []interface {} on left)
Adriano Tadao

2

यदि आपको अपने कोड को कम करने की आवश्यकता है, तो आप सहायक के लिए नए प्रकार बना सकते हैं

type Strings []string

func (ss Strings) ToInterfaceSlice() []interface{} {
    iface := make([]interface{}, len(ss))
    for i := range ss {
        iface[i] = ss[i]
    }
    return iface
}

फिर

a := []strings{"a", "b", "c", "d"}
sliceIFace := Strings(a).ToInterfaceSlice()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.