Bagaimana cara menentukan tipe "nyata" dari nilai {} antarmuka?


120

Saya belum menemukan sumber yang bagus untuk menggunakan interface{}tipe. Sebagai contoh

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

Apakah Anda mengetahui pengenalan yang baik untuk menggunakan Go interface{}?

pertanyaan spesifik:

  • bagaimana cara mendapatkan Tipe w yang "asli"?
  • apakah ada cara untuk mendapatkan representasi string dari suatu tipe?
  • apakah ada cara untuk menggunakan representasi string dari suatu tipe untuk mengonversi nilai?

Jawaban:


98

Teladan Anda berhasil. Ini versi yang disederhanakan.

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

Ini menggunakan pernyataan Jenis .


Anda memang benar! Terima kasih! apakah Anda memiliki wawasan tentang jenis representasi string jenis?
cc muda

12
Lihat reflect.TypeOf.
Dmitri Goldring

@DmitriGoldring Setidaknya menjawab pertanyaan di judul topik. Jawaban ini tidak. Terima kasih banyak.
C4d

130

Anda juga dapat melakukan sakelar tipe:

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

Terima kasih untuk itu. tapi masih belum cukup. dalam contoh, bagaimana cara memaksa var w menjadi int?
cc muda

3
Contoh Mue melakukan hal yang sama, tetapi dalam sakelar tipe, bukan pernyataan if. Dalam 'case int', 'v' akan menjadi integer. dalam 'case float64', 'v' akan menjadi float64, dll.
jimt

Baik. telah melupakan sintaks var. (tipe), yang licik dan keren
cc muda

51

Anda dapat menggunakan refleksi ( reflect.TypeOf()) untuk mendapatkan jenis sesuatu, dan nilai yang diberikannya ( Type) memiliki representasi string ( Stringmetode) yang dapat Anda cetak.


10
Dan jika Anda hanya ingin mendapatkan string atau tipe (mis. Untuk mencetak di blok default dari tautan sakelar tipe dalam jawaban Mue, Anda bisa menggunakan fmtformat "% T" daripada langsung menggunakan reflect.
Dave C

16

Berikut adalah contoh decoding peta generik menggunakan switch dan refleksi, jadi jika Anda tidak cocok dengan tipenya, gunakan refleksi untuk mencari tahu dan kemudian tambahkan tipe di lain waktu.

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

Sakelar tipe juga dapat digunakan dengan benda refleksi:

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

Saya akan menawarkan cara untuk mengembalikan boolean berdasarkan menyampaikan argumen Jenis refleksi ke penerima tipe lokal (karena saya tidak dapat menemukan yang seperti ini).

Pertama, kami mendeklarasikan tipe anonim kami dari tipe reflect. Nilai:

type AnonymousType reflect.Value

Kemudian kami menambahkan pembangun untuk tipe lokal AnonymousType kami yang dapat menerima tipe potensial apa pun (sebagai antarmuka):

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

Kemudian kami menambahkan fungsi untuk struct AnonymousType kami yang menegaskan terhadap sebuah reflect.

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

Ini memungkinkan kami untuk memanggil yang berikut:

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

Dapat melihat versi yang lebih lama dan berfungsi di sini: https://play.golang.org/p/EIAp0z62B7


1

Ada beberapa cara untuk mendapatkan representasi string dari suatu tipe. Sakelar juga dapat digunakan dengan jenis pengguna:

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

Tautan ke taman bermain: https://play.golang.org/p/VDeNDUd9uK6

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.