Bir arayüz {} değerinin "gerçek" türü nasıl belirlenir?


120

interface{}Türleri kullanmak için iyi bir kaynak bulamadım . Örneğin

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

Go'ları kullanmak için iyi bir giriş biliyor musunuz interface{}?

özel sorular:

  • w'nin "gerçek" türünü nasıl elde ederim?
  • bir türün dize temsilini almanın herhangi bir yolu var mı?
  • Bir değeri dönüştürmek için bir türün dize gösterimini kullanmanın herhangi bir yolu var mı?

Yanıtlar:


98

Örneğiniz işe yarıyor. İşte basitleştirilmiş bir versiyon.

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

Tür iddialarını kullanır .


kesinlikle haklısın! Teşekkürler! türlerin dizge temsilleri hakkında herhangi bir fikriniz var mı?
cc genç

12
Kontrol edin reflect.TypeOf.
Dmitri Goldring

@DmitriGoldring En azından konu başlığındaki soruyu yanıtlıyor. Bu cevap değil. Çok teşekkür ederim.
C4d

130

Ayrıca yazım anahtarları da yapabilirsiniz:

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.")
}

Bunun için teşekkür ederim. ama yine de tam olarak orada değil. Örnekte, var w'yi int'e nasıl zorlayabilirim?
cc genç

3
Mue'nin örneği de aynı şeyi yapar, ancak if ifadesi yerine bir tür anahtarında. 'Case int'de' v 'bir tamsayı olacaktır. 'float64 durumda', 'v' bir float64 vb. olacaktır
jimt

sağ. sinsi ve havalı sözdizimi değişkeni (tür) unutulmuştu
cc genç

51

Bir reflect.TypeOf()şeyin türünü almak için yansıma ( ) kullanabilirsiniz ve verdiği değer ( Type) Stringyazdırabileceğiniz bir dize temsiline ( yöntem) sahiptir.


10
Ve eğer sadece bir dizge veya tür elde etmek istiyorsanız (örneğin, Mue'nin cevabındaki bir tür değiştirme bağlantısının varsayılan bloğunda yazdırmak için fmt, doğrudan kullanmak yerine 's "% T" biçimini kullanabilirsiniz reflect.
Dave C

16

Burada, hem anahtar hem de yansıma kullanarak genel bir haritanın kodunu çözmenin bir örneği vardır, bu nedenle, türle eşleşmezseniz, anlamak için yansımayı kullanın ve bir dahaki sefere türü ekleyin.

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

Tip anahtarları ayrıca yansıma malzemesi ile kullanılabilir:

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

Yerel tip bir alıcıya bir yansıma Türleri argümanını iletmeye dayalı bir mantıksal değeri döndürmenin bir yolunu sunacağım (çünkü böyle bir şey bulamadım).

İlk olarak, anonim türümüzün yansıtıldığını beyan ederiz.

type AnonymousType reflect.Value

Ardından, yerel tür AnonymousType için herhangi bir potansiyel türü (arayüz olarak) alabilen bir oluşturucu ekliyoruz:

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

Ardından, AnonymousType yapımız için bir yansımaya karşı iddia eden bir işlev ekliyoruz.

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

Bu, aşağıdakileri aramamıza izin verir:

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")
}

Daha uzun, çalışan bir sürümü burada görebilirsiniz: https://play.golang.org/p/EIAp0z62B7


1

Bir türün dize gösterimini elde etmenin birçok yolu vardır. Anahtarlar ayrıca kullanıcı türleriyle de kullanılabilir:

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")
}

Bir oyun alanına bağlantı: https://play.golang.org/p/VDeNDUd9uK6

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.