Làm thế nào để xác định loại "thực" của giao diện {} value?


120

Tôi đã không tìm thấy một nguồn tài nguyên tốt để sử dụng interface{}các loại. Ví dụ

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

Bạn có biết giới thiệu hay về cách sử dụng Go's interface{}không?

Những câu hỏi cụ thể:

  • làm cách nào để lấy Loại w "thực"?
  • có cách nào để có được biểu diễn chuỗi của một kiểu không?
  • có cách nào để sử dụng biểu diễn chuỗi của một kiểu để chuyển đổi một giá trị không?

Câu trả lời:


98

Ví dụ của bạn không hoạt động. Đây là một phiên bản đơn giản hóa.

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

Nó sử dụng các xác nhận Kiểu .


bạn hoàn toàn đúng! cảm ơn! bạn có bất kỳ thông tin chi tiết nào về các kiểu biểu diễn chuỗi của các kiểu không?
cc trẻ

12
Kiểm tra reflect.TypeOf.
Dmitri Goldring

@DmitriGoldring Điều đó ít nhất trả lời câu hỏi trong tiêu đề chủ đề. Câu trả lời này không. Cảm ơn rât nhiều.
C4d

129

Bạn cũng có thể thực hiện chuyển đổi loại:

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

cảm ơn vì điều đó. nhưng vẫn chưa hoàn toàn ở đó. trong ví dụ, làm cách nào để ép var w thành một int?
cc trẻ

3
Ví dụ của Mue làm điều tương tự, nhưng trong một chuyển đổi kiểu thay vì một câu lệnh if. Trong 'case int', 'v' sẽ là một số nguyên. trong 'case float64', 'v' sẽ là float64, v.v.
jimt

đúng. đã quên cú pháp var. (type), một cách lén lút và mát mẻ
cc young

51

Bạn có thể sử dụng phản xạ ( reflect.TypeOf()) để nhận loại của một thứ gì đó và giá trị mà nó cung cấp ( Type) có một biểu diễn chuỗi ( Stringphương thức) mà bạn có thể in.


10
Và nếu bạn chỉ muốn lấy một chuỗi hoặc một kiểu (ví dụ: để in trong khối mặc định của liên kết chuyển đổi kiểu trong câu trả lời của Mue, bạn chỉ có thể sử dụng fmtđịnh dạng "% T" thay vì sử dụng trực tiếp reflect.
Dave C

16

Dưới đây là một ví dụ về giải mã một bản đồ chung bằng cách sử dụng cả chuyển đổi và phản chiếu, vì vậy nếu bạn không khớp với loại, hãy sử dụng phản chiếu để tìm ra và sau đó thêm loại vào lần sau.

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

Công tắc loại cũng có thể được sử dụng với nội dung phản chiếu:

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

Tôi sẽ đưa ra một cách để trả về một boolean dựa trên việc truyền một đối số của một kiểu phản chiếu tới một máy thu kiểu cục bộ (vì tôi không thể tìm thấy bất cứ thứ gì như thế này).

Đầu tiên, chúng tôi khai báo kiểu ẩn danh của chúng tôi là kiểu Refres.Value:

type AnonymousType reflect.Value

Sau đó, chúng tôi thêm một trình tạo cho loại cục bộ AnonymousType của chúng tôi, có thể sử dụng bất kỳ loại tiềm năng nào (làm giao diện):

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

Sau đó, chúng tôi thêm một hàm cho cấu trúc AnonymousType của chúng tôi, nó khẳng định chống lại một phản ánh.

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

Điều này cho phép chúng tôi gọi như sau:

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

Có thể xem phiên bản dài hơn, hoạt động tại đây: https://play.golang.org/p/EIAp0z62B7


1

Có nhiều cách để lấy biểu diễn chuỗi của một kiểu. Công tắc cũng có thể được sử dụng với các kiểu người dùng:

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

Liên kết đến sân chơi: https://play.golang.org/p/VDeNDUd9uK6

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.