एक इंटरफ़ेस {} मान का "वास्तविक" प्रकार कैसे निर्धारित करें?


120

मुझे interface{}प्रकारों का उपयोग करने के लिए एक अच्छा संसाधन नहीं मिला है । उदाहरण के लिए

package main

import "fmt"

func weirdFunc(i int) interface{} {
    if i == 0 {
        return "zero"
    }
    return i
}
func main() {
    var i = 5
    var w = weirdFunc(5)

    // this example works!
    if tmp, ok := w.(int); ok {
        i += tmp
    }

    fmt.Println("i =", i)
}

क्या आपको गो के इस्तेमाल से अच्छे परिचय का पता है interface{}?

विशिष्ट प्रश्न:

  • मुझे "वास्तविक" प्रकार का w कैसे मिलेगा?
  • क्या किसी प्रकार का स्ट्रिंग प्रतिनिधित्व प्राप्त करने का कोई तरीका है?
  • मान को परिवर्तित करने के लिए किसी प्रकार के स्ट्रिंग प्रतिनिधित्व का उपयोग करने का कोई तरीका है?

जवाबों:


98

आपका उदाहरण काम करता है। यहाँ एक सरलीकृत संस्करण है।

package main

import "fmt"

func weird(i int) interface{} {
    if i < 0 {
        return "negative"
    }
    return i
}

func main() {
    var i = 42
    if w, ok := weird(7).(int); ok {
        i += w
    }
    if w, ok := weird(-100).(int); ok {
        i += w
    }
    fmt.Println("i =", i)
}

Output:
i = 49

इसमें टाइप असेसरीज का उपयोग किया जाता है ।


आप बिल्कुल सही कह रहे है! धन्यवाद! क्या आपके पास प्रकारों के स्ट्रिंग प्रतिनिधित्व पर कोई अंतर्दृष्टि है?
सीसी युवा

12
जांच करें reflect.TypeOf
दिमित्री गोल्डिंग

@DmitriGoldring यह कि विषय शीर्षक में कम से कम सवाल का जवाब देता है। यह उत्तर नहीं। आपका बहुत बहुत धन्यवाद।
C4d

129

आप टाइप स्विच भी कर सकते हैं:

switch v := myInterface.(type) {
case int:
    // v is an int here, so e.g. v + 1 is possible.
    fmt.Printf("Integer: %v", v)
case float64:
    // v is a float64 here, so e.g. v + 1.0 is possible.
    fmt.Printf("Float64: %v", v)
case string:
    // v is a string here, so e.g. v + " Yeah!" is possible.
    fmt.Printf("String: %v", v)
default:
    // And here I'm feeling dumb. ;)
    fmt.Printf("I don't know, ask stackoverflow.")
}

उसके लिये आपका धन्यवाद। लेकिन अभी भी वहाँ नहीं है। उदाहरण में, मैं var को int में कैसे ले सकता हूं?
सीसी युवा

3
Mue का उदाहरण एक ही काम करता है, लेकिन एक प्रकार के स्विच में एक if स्टेटमेंट के बजाय। 'केस इंट' में, 'v' एक पूर्णांक होगा। 'केस फ्लोट64' में, 'वी' एक फ्लोट64 होगा, आदि
jimt

सही। सिंटैक्स var को भूल गए (प्रकार), जो डरपोक और शांत है
cc युवा

51

आप किसी reflect.TypeOf()चीज़ के प्रकार को प्राप्त करने के लिए प्रतिबिंब ( ) का उपयोग कर सकते हैं , और इसके द्वारा दिए जाने वाले मूल्य ( Type) में एक स्ट्रिंग प्रतिनिधित्व ( Stringविधि) है जिसे आप प्रिंट कर सकते हैं।


10
और यदि आप केवल एक स्ट्रिंग या एक प्रकार प्राप्त करना चाहते हैं (जैसे कि म्यु के उत्तर में एक प्रकार के स्विच लिंक के डिफ़ॉल्ट ब्लॉक में मुद्रण के लिए तो आप fmtसीधे उपयोग करने के बजाय केवल "s"% T "प्रारूप का उपयोग कर सकते हैं reflect
डेव सी

16

यहां स्विच और प्रतिबिंब दोनों का उपयोग करके एक जेनेरिक मानचित्र को डिकोड करने का एक उदाहरण है, इसलिए यदि आप प्रकार से मेल नहीं खाते हैं, तो इसे पता लगाने के लिए प्रतिबिंब का उपयोग करें और फिर अगली बार में प्रकार जोड़ें।

var data map[string]interface {}

...

for k, v := range data {
    fmt.Printf("pair:%s\t%s\n", k, v)   

    switch t := v.(type) {
    case int:
        fmt.Printf("Integer: %v\n", t)
    case float64:
        fmt.Printf("Float64: %v\n", t)
    case string:
        fmt.Printf("String: %v\n", t)
    case bool:
        fmt.Printf("Bool: %v\n", t)
    case []interface {}:
        for i,n := range t {
            fmt.Printf("Item: %v= %v\n", i, n)
        }
    default:
        var r = reflect.TypeOf(t)
        fmt.Printf("Other:%v\n", r)             
    }
}

6

प्रतिबिंब सामग्री के साथ टाइप स्विच का भी उपयोग किया जा सकता है:

var str = "hello!"
var obj = reflect.ValueOf(&str)

switch obj.Elem().Interface().(type) {
case string:
    log.Println("obj contains a pointer to a string")
default:
    log.Println("obj contains something else")
}

2

मैं एक प्रतिबिंब को एक प्रकार का एक स्थानीय प्रकार रिसीवर (क्योंकि मैं इस तरह से कुछ भी नहीं मिल सकता है) के एक तर्क के आधार पर एक बूलियन को वापस करने की पेशकश करने जा रहा हूं।

सबसे पहले, हम अपने अनाम प्रकार को दर्शाते हैं।

type AnonymousType reflect.Value

फिर हम अपने स्थानीय प्रकार बेनामी टाइप के लिए एक बिल्डर जोड़ते हैं जो किसी भी संभावित प्रकार (एक इंटरफ़ेस के रूप में) में ले सकता है:

func ToAnonymousType(obj interface{}) AnonymousType {
    return AnonymousType(reflect.ValueOf(obj))
}

फिर हम अपनी बेनामी टाइप संरचना के लिए एक फ़ंक्शन जोड़ते हैं जो एक परावर्तित के खिलाफ जोर देता है। हिंद:

func (a AnonymousType) IsA(typeToAssert reflect.Kind) bool {
    return typeToAssert == reflect.Value(a).Kind()
}

यह हमें निम्नलिखित कॉल करने की अनुमति देता है:

var f float64 = 3.4

anon := ToAnonymousType(f)

if anon.IsA(reflect.String) {
    fmt.Println("Its A String!")
} else if anon.IsA(reflect.Float32) {
    fmt.Println("Its A Float32!")
} else if anon.IsA(reflect.Float64) {
    fmt.Println("Its A Float64!")
} else {
    fmt.Println("Failed")
}

यहां एक लंबा, कामकाजी संस्करण देख सकते हैं: https://play.golang.org/p/EIAp0z62B7


1

एक प्रकार का एक स्ट्रिंग प्रतिनिधित्व प्राप्त करने के कई तरीके हैं। स्विच का उपयोग उपयोगकर्ता प्रकारों के साथ भी किया जा सकता है:

var user interface{}
user = User{name: "Eugene"}

// .(type) can only be used inside a switch
switch v := user.(type) {
case int:
    // Built-in types are possible (int, float64, string, etc.)
    fmt.Printf("Integer: %v", v)
case User:
    // User defined types work as well  
    fmt.Printf("It's a user: %s\n", user.(User).name)
}

// You can use reflection to get *reflect.rtype
userType := reflect.TypeOf(user)
fmt.Printf("%+v\n", userType)

// You can also use %T to get a string value
fmt.Printf("%T", user)

// You can even get it into a string
userTypeAsString := fmt.Sprintf("%T", user)

if userTypeAsString == "main.User" {
    fmt.Printf("\nIt's definitely a user")
}

एक खेल के मैदान से लिंक: https://play.golang.org/p/VDeNDUd9uK6

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