【问题标题】:using reflection in Go to get the name of a struct在 Go 中使用反射来获取结构的名称
【发布时间】:2016-06-17 21:16:16
【问题描述】:

我发现这个问题的答案很好:

How to find a type of a object in Golang?

我玩弄了答案,并尝试以相同的方式获取结构的名称:

package main

import (
        "fmt"
        "reflect"
)

type Ab struct {

}

func getType(myvar interface{}) string {
        return reflect.TypeOf(myvar).Name()
}

func main() {
        fmt.Println("Hello, playground")

        tst := "string"
        tst2 := 10
        tst3 := 1.2
        tst4 := new(Ab)

        fmt.Println(getType(tst))
        fmt.Println(getType(tst2))
        fmt.Println(getType(tst3))
        fmt.Println(getType(tst4))

}

去游乐场:http://play.golang.org/p/tD8mygvETH

但是输出是:

Hello, playground
string
int
float64


Program exited.

预期的输出是:

Hello, playground
string
int
float64
Ab

Program exited.

我试图通过阅读文档来弄清楚,但没有找到关于此的问题。所以,很抱歉这个非常笼统的问题,但是:

什么原因,reflect.TypeOf().Name() 不适用于(这个)结构?

【问题讨论】:

  • 似乎如果你做 Ab{},而不是 new(Ab) 你会得到预期的结果

标签: go struct reflection types


【解决方案1】:

fmt 还有一个很酷的%T 标签

package main

import (
    "fmt"
    "net/http"
)

type Potato struct {
}

func main() {
    fmt.Printf("I have a %T, an %T and a %T\n", Potato{}, http.StatusMultipleChoices, &http.Response{})
}

输出I have a main.Potato, an int and a *http.Response https://play.golang.org/p/6z7_0BSitm

【讨论】:

    【解决方案2】:

    在您的示例中,您传递的是指针类型 (*Ab) 的值,而不是结构类型。

    坚持Type.Name()

    如果不是指针,Type.Name() 将正确返回Ab。如果是指针,如果你仍然想要结构的名称,你可以使用Type.Elem() 来获取元素的类型:

    func getType(myvar interface{}) string {
        if t := reflect.TypeOf(myvar); t.Kind() == reflect.Ptr {
            return "*" + t.Elem().Name()
        } else {
            return t.Name()
        }
    }
    

    测试它:

    tst4 := Ab{}
    tst5 := new(Ab)
    fmt.Println(getType(tst4))
    fmt.Println(getType(tst5))
    

    输出(在Go Playground 上尝试修改后的示例):

    Ab
    *Ab
    

    注意:

    请注意,由于Type.Name() 不解析指针,因此如果传递的值是指向指针的指针,它将不起作用,例如**Ab,而 Type.String() 自动解析指针,在这种情况下也可以工作。

    我们可以很容易地使我们的getType() 函数也与**Ab 一起工作(或任何深度的指针):

    func getType(myvar interface{}) (res string) {
        t := reflect.TypeOf(myvar)
        for t.Kind() == reflect.Ptr {
            t = t.Elem()
            res += "*"
        }
        return res + t.Name()
    }
    

    用值调用它:

    tst4 := Ab{}
    tst5 := new(Ab)
    tst6 := &tst5 // type of **Ab
    tst7 := &tst6 // type of ***Ab
    

    输出(在Go Playground上试试):

    Ab
    *Ab
    **Ab
    ***Ab
    

    使用Type.String()

    更简单更好的方法是使用Type.String() 而不是Type.Name(),后者会自动处理指针并包含包名。例如:

    func getType(myvar interface{}) string {
        return reflect.TypeOf(myvar).String()
    }
    

    对于修改后的例子,它输出:

    string
    int
    float64
    main.Ab
    *main.Ab
    

    在Go Playground 上试试这个变体。

    【讨论】:

    • 谢谢。这个答案简直太美了
    • 第二种选择也适用于例如**Ab,第一个没有。
    • @DanieleD 添加到答案中,并展示了它如何仍可用于支持**Ab(或任何深度的指针)。
    【解决方案3】:

    问题是new返回指针,下面应该会得到想要的结果。

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type Ab struct {
    }
    
    func getType(myvar interface{}) {
        valueOf := reflect.ValueOf(myvar)
    
        if valueOf.Type().Kind() == reflect.Ptr {
            fmt.Println(reflect.Indirect(valueOf).Type().Name())
        } else {
            fmt.Println(valueOf.Type().Name())
        }
    }
    
    func main() {
        fmt.Println("Hello, playground")
    
        tst := "string"
        tst2 := 10
        tst3 := 1.2
        tst4 := new(Ab)
    
        getType(tst)
        getType(tst2)
        getType(tst3)
        getType(tst4)
    
    }
    

    输出是

    Hello, playground
    string
    int
    float64
    Ab
    

    【讨论】:

      猜你喜欢
      • 2014-08-11
      • 2012-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-06
      • 2018-04-24
      • 2015-01-01
      • 1970-01-01
      相关资源
      最近更新 更多