go语言 反射

为何需要反射?

下面例子试图打印出传入的interface值,无法找到无尽的未知类型的表示方式,我们被卡住了。这就是我们为何需要反射的原因。

func Sprint(x interface{}) string {
    type stringer interface {
        String() string
    }
    switch x := x.(type) {
    case stringer:
        return x.String()
    case string:
        return x
    case int:
        return strconv.Itoa(x)
    // ...similar cases for int16, uint32, and so on...
    case bool:
        if x {
            return "true"
        }
        return "false"
    default:
        // array, chan, func, map, pointer, slice, struct
        return "???"
    }
}
reflect.Type与reflect.Value
reflect.Type //表示一个go类型
reflect.Value //表示一个任意类型的值

函数 reflect.TypeOf 接受任意的 interface{} 类型,并以 reflect.Type 形式返回其动态类型:

t := reflect.TypeOf(3)  // a reflect.Type
fmt.Println(t.String()) // "int"
fmt.Println(t)          // "int"

因为 reflect.TypeOf 返回的是一个动态类型的接口值,它总是返回具体的类型。

var w io.Writer = os.Stdout
fmt.Println(reflect.TypeOf(w)) // "*os.File"

函数 reflect.ValueOf 接受任意的 interface{} 类型,并返回一个装载着其动态值的 reflect.Value

v := reflect.ValueOf(3) // a reflect.Value
fmt.Println(v)          // "3"
fmt.Printf("%v\n", v)   // "3"
fmt.Println(v.String()) // NOTE: "<int Value>"

对 Value 调用 Type 方法将返回具体类型所对应的 reflect.Type:

t := v.Type()           // a reflect.Type
fmt.Println(t.String()) // "int"

reflect.ValueOf 的逆操作是 reflect.Value.Interface 方法。它返回一个 interface{} 类型,装载着与 reflect.Value 相同的具体值:

v := reflect.ValueOf(3) // a reflect.Value.  v:3
x := v.Interface()      // an interface{}. x:3
i := x.(int)            // an int. I:3
fmt.Printf("%d\n", i)   // "3"

我们使用 reflect.Value 的 Kind 方法来替代之前的类型 switch。虽然还是有无穷多的类型,但是它们的 kinds 类型却是有限的:Bool、String 和 所有数字类型的基础类型;Array 和 Struct 对应的聚合类型;Chan、Func、Ptr、Slice 和 Map 对应的引用类型;interface 类型;还有表示空值的 Invalid 类型。(空的 reflect.Value 的 kind 即为 Invalid。)

package format

import (
    "reflect"
    "strconv"
)

// Any formats any value as a string.
func Any(value interface{}) string {
    return formatAtom(reflect.ValueOf(value))
}

// formatAtom formats a value without inspecting its internal structure.
func formatAtom(v reflect.Value) string {
    switch v.Kind() {
    case reflect.Invalid:
        return "invalid"
    case reflect.Int, reflect.Int8, reflect.Int16,
        reflect.Int32, reflect.Int64:
        return strconv.FormatInt(v.Int(), 10)
    case reflect.Uint, reflect.Uint8, reflect.Uint16,
        reflect.Uint32, reflect.Uint64, reflect.Uintptr:
        return strconv.FormatUint(v.Uint(), 10)
    // ...floating-point and complex cases omitted for brevity...
    case reflect.Bool:
        return strconv.FormatBool(v.Bool())
    case reflect.String:
        return strconv.Quote(v.String())
    case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Slice, reflect.Map:
        return v.Type().String() + " 0x" +
            strconv.FormatUint(uint64(v.Pointer()), 16)
    default: // reflect.Array, reflect.Struct, reflect.Interface
        return v.Type().String() + " value"
    }
}

reflect.Value 的 FieldByName方法

type Foo struct {
⇥   X string
⇥   Y int
}

func main() {

⇥   var foo = Foo{"abc", 123}

⇥   val := reflect.ValueOf(foo)
⇥   fmt.Println(val.FieldByName("a")) //<invalid reflect.Value>
⇥   //fmt.Println(val.FieldByName("a").Interface()) //报错
⇥   fmt.Println("==?", val.FieldByName("a") == reflect.ValueOf(nil))
⇥   fmt.Println("==?", val.FieldByName("a").Kind() == reflect.Invalid)

⇥   typ := reflect.TypeOf(foo)
⇥   fmt.Println(typ.FieldByName("a")) //{  <nil>  0 [] false} false StructField对象
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 首先巴拉巴拉一下golang反射机制的三个定律 1.反射可以从接口类型到反射类型对象 2.反射可以从反射类型对象到...
    吃猫的鱼0阅读 3,103评论 0赞 1
  • 第一次知道反射的时候还是许多年前在学校里玩 C# 的时候。那时总是弄不清楚这个复杂的玩意能有什么实际用途……然后发...
    勿以浮沙筑高台阅读 1,211评论 0赞 9
  • 为何需要使用 reflect 获取:减少重复代码 1. API 接口中抽取参数的逻辑大量重复   API 接口自然...
    blackpiglet阅读 1,381评论 0赞 5
  • 今天看了吴亦凡的《有一个地方只有我们知道》。2个老人的爱情故事是主体,2个年青人最后因为老人的爱情故事得到了教训,...
    cherry凡阅读 224评论 0赞 0
  • 向日葵,朝着阳光生长,代表着光明与美好,灿烂阳光。 临摹书籍《飞乐鸟·花卉绘》 工具:辉柏嘉水溶48色彩铅,樱花自...
    珏音Raya阅读 2,020评论 0赞 6

友情链接更多精彩内容