इंटरफ़ेस पर रेंज {} जो एक स्लाइस को स्टोर करता है


99

परिदृश्य को देखते हुए जहां आपके पास एक फ़ंक्शन है जो स्वीकार करता है t interface{}। यदि यह निर्धारित किया जाता है कि tएक टुकड़ा है, तो मैं rangeउस टुकड़ा पर कैसे करूँ ?

func main() {
    data := []string{"one","two","three"}
    test(data)
    moredata := []int{1,2,3}
    test(data)
}

func test(t interface{}) {
    switch reflect.TypeOf(t).Kind() {
    case reflect.Slice:
        // how do I iterate here?
        for _,value := range t {
            fmt.Println(value)
        }
    }
}

खेल का मैदान उदाहरण देखें: http://play.golang.org/p/DNldAlNShB


फ़ंक्शन को इसके बजाय [] इंटरफ़ेस {} क्यों नहीं लिया जाता है? क्या आप कई जटिल प्रकारों को संभालने की कोशिश कर रहे हैं?
जेरेमी वॉल

2
हां, यह एक टेम्प्लेटिंग सिस्टम के लिए है, इसलिए {} एक मैप, स्ट्रक्चर, स्लाइस या एरे हो सकता है। वास्तविक कोड में कई और केस स्टेटमेंट हैं, लेकिन मैंने उन्हें समस्या को अधिक संक्षिप्त बनाने के लिए पद से हटा दिया।
न्यूक्लियॉन

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

@JeremyWall आप स्लाइस के रूप में कार्य करने के लिए [] इंटरफ़ेस {} का उपयोग नहीं कर सकते। आप यहाँ देख सकते हैं ।
फायरली

जवाबों:


138

वैसे मैंने इस्तेमाल किया reflect.ValueOfऔर फिर अगर यह एक स्लाइस है जिसे आप कॉल कर सकते हैं Len()और एक इंडेक्स पर स्लाइस और एलिमेंट Index()पाने के लिए len। मुझे नहीं लगता कि आप ऐसा करने के लिए रेंज ऑपरेट का उपयोग कर पाएंगे।

package main

import "fmt"
import "reflect"

func main() {
    data := []string{"one","two","three"}
    test(data)
    moredata := []int{1,2,3}
    test(moredata)
} 

func test(t interface{}) {
    switch reflect.TypeOf(t).Kind() {
    case reflect.Slice:
        s := reflect.ValueOf(t)

        for i := 0; i < s.Len(); i++ {
            fmt.Println(s.Index(i))
        }
    }
}

Go Playground उदाहरण: http://play.golang.org/p/gQhCTiwPAq


25
महान काम करता है, धन्यवाद। जोड़ने के लिए केवल एक चीज यह होगी कि मेरे मामले में s.Index(i)रिटर्न reflect.Valueमुझे s.Index(i).Interface()वास्तविक मूल्य के संदर्भ में चाहिए।
न्यूक्लॉन

1
यदि आप एक स्लाइस में एक सूचक था तो आप क्या करेंगे interface{}? जैसे moredata := &[]int{1,2,3}
रायन वाल्स ने

1
मेरे प्रश्न का उत्तर देना: यदि आपके पास एक स्लाइस के बजाय एक स्लाइस का सूचक है, तो आपको Elem()अंतर्निहित मूल्य प्राप्त करने के लिए उपयोग करना होगा। जैसे reflect.TypeOf(reflect.ValueOf(t).Elem().Interface()).Kind()
रायन वाल्स

क्या होगा अगर मैं बिना किसी संरचना के इंटरफ़ेस के स्लाइस से इंटरफ़ेस फ़ील्ड का मूल्य प्राप्त करना चाहता हूं। मैंने इस समाधान की कोशिश की है, लेकिन यह केवल स्लाइस से इंटरफ़ेस संदर्भ प्राप्त करने के लिए सीमित है न कि खेतों के वास्तविक मूल्य।
अमनदीप कौर

वाह बहुत धन्यवाद, उस चाल ने मुझे बहुत समय (और सिरदर्द!) बचाया
निकोलस गार्नियर

26

यदि आपको पता है कि किस प्रकार की अपेक्षा करनी है तो आपको प्रतिबिंब का उपयोग करने की आवश्यकता नहीं है। आप एक प्रकार स्विच का उपयोग कर सकते हैं , जैसे:

package main

import "fmt"

func main() {
    loop([]string{"one", "two", "three"})
    loop([]int{1, 2, 3})
}

func loop(t interface{}) {
    switch t := t.(type) {
    case []string:
        for _, value := range t {
            fmt.Println(value)
        }
    case []int:
        for _, value := range t {
            fmt.Println(value)
        }
    }
}

खेल के मैदान पर कोड देखें


यह एक सरणी पर काम नहीं करेगा, केवल एक स्लाइस पर
user1028741

@ user1028741 नहीं, कोड सरण सहित हर प्रकार के लिए काम करता है + आप हमेशा एक सरणी से एक टुकड़ा ले सकते हैं array[:]
22

लेकिन एक सरणी का प्रकार इसकी वास्तविक क्षमता के साथ होगा। [३] int समान प्रकार का नहीं है [२] int या [] int। इसलिए, यदि 't' का प्रकार वास्तव में एक सरणी है तो प्रासंगिक मामला लागू नहीं होगा।
user1028741

1
मेरा मतलब है कि आपका उदाहरण सरणियों पर काम नहीं करेगा। मैंने इसे यहां बदल दिया: play.golang.org/p/DAsg_0aXz-r
user1028741

यदि आप पहली बार में अपने पैरामीटर के प्रकार को नहीं जानते हैं, तो आप इसे आसानी से काम नहीं कर सकते। अपनी चाल (सरणी [:]) का उपयोग करने के लिए, आपको यह तय करने के लिए प्रतिबिंब का उपयोग करना होगा कि यह एक सरणी है, फिर सरणी के लिए - फिर इसका एक टुकड़ा उत्पन्न करें। इसलिए मैंने कहा कि यह एक स्लाइस पर काम करता है, किसी ऐरे पर नहीं। स्पष्ट रूप से पर्याप्त प्रयास से आप सरणी से एक स्लाइस का उत्पादन कर सकते हैं ...
user1028741

4

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

package main

import (
    "fmt"
)

type interfaceSliceType []interface{}

var interfaceAsSlice interfaceSliceType

func main() {
    loop(append(interfaceAsSlice, 1, 2, 3))
    loop(append(interfaceAsSlice, "1", "2", "3"))
    // or
    loop([]interface{}{[]string{"1"}, []string{"2"}, []string{"3"}})
    fmt.Println("------------------")


    // and of course one such slice can hold any type
    loop(interfaceSliceType{"string", 999, map[int]string{3: "three"}})
}

func loop(slice []interface{}) {
    for _, elem := range slice {
        switch elemTyped := elem.(type) {
        case int:
            fmt.Println("int:", elemTyped)
        case string:
            fmt.Println("string:", elemTyped)
        case []string:
            fmt.Println("[]string:", elemTyped)
        case interface{}:
            fmt.Println("map:", elemTyped)
        }
    }
}

उत्पादन:

int: 1
int: 2
int: 3
string: 1
string: 2
string: 3
[]string: [1]
[]string: [2]
[]string: [3]
------------------
string: string
int: 999
map: map[3:three]

कोशिश करके देखो

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.