使用反射在Go语言中获取结构体的名称。

huangapple go评论108阅读模式
英文:

using reflection in Go to get the name of a struct

问题

我找到了这个问题和这些很好的答案:

https://stackoverflow.com/questions/20170275/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))

}

Go playground: http://play.golang.org/p/tD8mygvETH

但是输出结果是:

Hello, playground
string
int
float64


Program exited.

期望的输出结果应该是:

Hello, playground
string
int
float64
Ab

Program exited.

我尝试通过阅读文档来找出问题所在,但没有找到关于这个问题的解释。所以,对于这个非常普遍的问题,我很抱歉,但是:

为什么 reflect.TypeOf().Name() 在这个结构体中不起作用?

英文:

I found this question with this great answers:

https://stackoverflow.com/questions/20170275/how-to-find-a-type-of-a-object-in-golang

I played around with the answer and tried to get the name of a struct in the same way:

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

}

Go playground: http://play.golang.org/p/tD8mygvETH

But the output is:

Hello, playground
string
int
float64


Program exited.

Expected output would be:

Hello, playground
string
int
float64
Ab

Program exited.

I tried to figure out by reading the documentation but didn't find the issue about that. So, sorry for the very general question, but:

What's the reason, reflect.TypeOf().Name() does not work with (this) struct(s)?

答案1

得分: 86

在你的示例中,你传递的是指针类型的值(*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 // **Ab的类型
tst7 := &tst6 // ***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上尝试这个变体。

英文:

In your example you pass a value of pointer type (*Ab), not a struct type.

Sticking to Type.Name()

If it is not a pointer, Type.Name() will properly return Ab. In case of pointer if you still want the struct's name, you can use Type.Elem() to get the element's type:

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

Testing it:

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

Output (try your modified example on the Go Playground):

Ab
*Ab

Note:

Note that as Type.Name() does not resolve pointers, it would not work if the value passed is a pointer to pointer, e.g. **Ab, while as Type.String() automatically resolves pointers, would work in this case too.

We can easily make our getType() function to work with **Ab too (or with any depth of pointers):

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

Calling it with values:

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

Output (try it on the Go Playground):

Ab
*Ab
**Ab
***Ab

Using Type.String()

A simpler and better approach would be to use Type.String() instead of Type.Name() which automatically handles pointers and also includes package name. E.g.:

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

For the modified example it outputs:

string
int
float64
main.Ab
*main.Ab

Try this variant on the Go Playground.

答案2

得分: 21

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

package main

import (
	"fmt"
	"net/http"
)

type Potato struct {
}

func main() {
	fmt.Printf("我有一个%T,一个%T和一个%T\n", Potato{}, http.StatusMultipleChoices, &http.Response{})
}

输出结果为我有一个main.Potato,一个int和一个*http.Response
链接:https://play.golang.org/p/6z7_0BSitm

英文:

fmt has a cool %T tag as well

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

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

答案3

得分: 4

问题是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
英文:

The problem is new returns pointer, following should get the desired result.

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)

}

Output is

Hello, playground
string
int
float64
Ab

huangapple
  • 本文由 发表于 2016年3月4日 16:05:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/35790935.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定