前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go语言学习之reflect

go语言学习之reflect

作者头像
张宗伟 plus
发布2023-01-04 14:07:34
2530
发布2023-01-04 14:07:34
举报
文章被收录于专栏:张宗伟 plus张宗伟 plus

本学习笔记全部以代码块的形式展示,具体的内容都包含在代码里:

代码语言:javascript
复制
package types

import (
  "fmt"
  "reflect"
)

// 1. reflect 是用程序检查其所拥有的结构,尤其是类型的一种能力;这是元编程的一种形式。
//     反射可以在运行时检查类型和变量,例如它的大小、方法,并且能动态的调用其中的方法。
//  2. reflect.TypeOf 和 reflect.ValueOf,返回被检查对象的类型和值。
// 3. 原理上,反射是通过检查一个接口的值,变量首先被转换成空接口。
// 4. 反射可以从接口值反射到对象,也可以从对象反射回接口值。
// 5. reflect.Type 和 reflect.Value 都有许多方法用于检查和操作自身
// 6. 利用reflect 可以更改对象值,反射中有些内容是需要用地址去改变它的状态的。
// 7. reflect 可以反射结构struct。

// 定义 NotKnownType
type NotKnownType struct {
  a, b, c string
}

// 定义方法
func (n NotKnownType) GetStr() string {
  return n.a + n.b + n.c
}
func (n NotKnownType) GetStr1(str string) string {
  return n.a + n.b + n.c + str
}

// 定义 NotKnownType
type NotKnownType1 struct {
  A, B, C string
}

func ReflectExample() {
  var x int8 = 10
  // t 是 reflect.Type 类型
  t := reflect.TypeOf(x)
  // v 是 reflect.Value 类型
  v := reflect.ValueOf(x)

  fmt.Println("t: ", t)
  fmt.Println("v: ", v)

  // 5
  fmt.Println("reflect.Value.Type: ", v.Type())
  // Kind 方法总是返回底层类型
  fmt.Println("reflect.Type.Kind, reflect.Value.Kind: ", t.Kind(), v.Kind(), t.Kind() == reflect.Int8)
  fmt.Println("reflect.Value.Int: ", v.Int())

  // 6
  // 使用 CanSet 判断是否可以更改值
  fmt.Println("reflect.Value.CanSet: ", v.CanSet())
  // 上述得到的是 false,因为 v 是通过 x 的拷贝创建的,改变 v 并不能改变 x,所以要使用 x的地址
  v1 := reflect.ValueOf(&x)
  fmt.Println("v1: ", v1, v1.Type())
  // 这时还是不能更改值
  fmt.Println("reflect.Value.CanSet: ", v1.CanSet())
  // 还需要使用 Elem()
  v1 = v1.Elem()
  fmt.Println("reflect.Value.CanSet: ", v1.CanSet())
  // 更改值
  v1.SetInt(20)
  fmt.Println("reflect.Value.SetInt: ", v1, x)

  // 7
  // 假设不知道 n 具体的struct类型
  var n interface{} = NotKnownType{"a", "b", "c"}
  t2 := reflect.TypeOf(n)
  v2 := reflect.ValueOf(n)

  fmt.Println("t2: ", t2)
  fmt.Println("v3: ", v2)

  // 可使用 NumField 返回结构体的字段数量,使用 Field 得到该字段的值
  for i := 0; i < v2.NumField(); i++ {
    fmt.Printf("reflect.Value.Field %d: %v\n", i, v2.Field(i))
  }
  // 使用 Method(n).Call(nil) 调用结构体中的方法
  m1 := v2.Method(0).Call(nil)
  param := []reflect.Value{reflect.ValueOf("d")}
  m2 := v2.Method(1).Call(param)
  fmt.Printf("m1: %v, m2: %v\n", m1, m2)

  // 当更改struct字段时,字段必须可导出(即首字母要大写),然后结合上述更改的规则
  n1 := NotKnownType1{"A", "B", "C"}
  v3 := reflect.ValueOf(&n1)
  v3 = v3.Elem()
  fmt.Println("reflect.Value.CanSet: ", v3.CanSet())
  for i := 0; i < v3.NumField(); i++ {
    origin := v3.Field(i)
    v3.Field(i).SetString(origin.String() + origin.String())
  }
  fmt.Println("n1: ", n1)
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-10-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 张宗伟 plus 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档