后浪笔记一零二四

变量和常量

变量和常量

  • 使用一个名称来绑定一块内存地址,该内存地址中存放的数据类型由定义变量时指定的类型决定
    • 变量:该内存地址里面存放的内容可以改变
    • 常量:该内存地址里面存放的内容不可以改变
      • 常量存储在程序的只读段中(.rodata section)
  • 存储和生存期:
    • Go语言提供自动内存管理,通常程序员不需要特别关注变量的生存期和存放位置
    • 编译器使用栈逃逸技术能够自动为变量分配空间

反射的API

  • 所有类型通用的方法,对于未命名类型返回为空

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    // 返回包含包名的类型名字,对于未命名类型返回的是空
    Name() string
    // Kind返回该类型的底层基础类型,和底层类型不同,底层类型关注的是赋值和类型转化问题的。
    Kind() Kind
    // 确定当前类型是否实现了u接口类型
    // 注意这里的u必须是接口类型的Type
    Implements(u Type) bool
    // 判断当前类型的实例是否能赋值给type为u的类型变量 (和底层类型相关)
    AssignableTo(u Type) bool
    // 判断当前类型的实例是否能强制类型转换为u类型变量
    ConvertibleTo(u Type) bool
    // 判断当前类型是否支持比较
    // 支持比较的类型可以作为map的key
    Comparable() bool
    // 返回一个类型的方法的个数
    NumMethod() int
    // 通过索引值访问方法,索引值必须属于[0, NumMethod()],否则引发panic
    Method(int) Method
    // 通过方法名获取Method
    MethodByName(string) (Method, bool)
    // 返回类型的包路径,如果类型是预声明类型或者未命名类型,则返回空字符串
    PkgPath() string
    // 返回存放该类型的实例需要多大的字节空间
    Size() uintptr
    
  • 不同基础类型(底层基础类型)的专有方法

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    // Int*, Uint*, Float*, Complex*: Bits
    // Array: Elem, Len
    // Chan: ChanDir, Elem
    // Func: In, NumIn, Out, NumOut, IsVariadic.
    // Map: Key, Elem
    // Ptr: Elem
    // Slice: Elem
    // Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField
    // 返回类型的元素类型,该方法只适合Array、Chan、Map、Ptr、Slice类型
    Elem() Type
    // 返回数值型类型内存占用的位数
    Bits() int
    // struct类型专有的方法
    // 返回字段数目
    NumField() int
    // 通过整数索引获取struct字段
    Field(i int) StructField
    // 获取嵌入字段获取struct字段
    FieldByIndex(index []int) StructField
    // 通过名字查找获取struct字段
    FieldByName(name string) (StructField, bool)
    // func类型专有的方法
    // 函数是否是不定参数函数
    IsVariadic() bool
    // 输入参数个数
    NumIn() int
    // 返回值个数
    NumOut() int
    // 返回第i个输入参数类型
    In(i int) Type
    // 返回第i个返回值类型
    Out(i int) Type
    // map类型专用的方法
    // 返回map key的type
    Key() Type
    
  1. 从实例到Value 通过实例获取Value对象,直接使用reflect.ValueOf()函数,例如:
1
func ValueOf(i interface{}) Value
  1. 从实例到Type 通过实例获取反射对象的Type,直接使用reflect.TypeOf()函数,例如:
1
func TypeOf(i interface{}) Type
  1. 从Type到Value Type里面只有类型信息,所以直接从一个Type接口变量里面是无法获得实例的Value的,但是 可以通过该Type构建一个新实例的Value。reflect包提供了两种方法,示例如下:
1
2
3
4
5
// New返回的是一个Value,该Value的type为PtrTo(typ),即Value的Type是指定typ的指针类型
func New(typ Type) Value

// Zero返回的是一个typ类型的零值,注意返回的Value不能寻址,值不可重复
func Zero(typ Type) Value

如果知道一个类型值的底层存放地址,则还有一个函数是可以依据Type和该地址值恢复出Value的,例如

1
func NewAt(typ Type, p unsafe.Pointer) Value
  1. 从Value到Type 从反射对象Value到Type可以直接调用Value的方法,因为Value内部存放看到Type类型的指针,例如:
1
func (v Value) Type() Type
  1. 从Value到实例 Value本身就包含类型和值信息,reflect提供了丰富的方法来实现从Value到实例的转换。 例如:
1
2
3
4
5
6
7
8
9
// 该方法最通用、用来将Value转换为借口,该空接口内部存放具体类型实例
// 可以使用接口类型查询去还原为具体的类型
func (v Value) Interface() (i interface{})

// Value自身也提供丰富的方法,直接将Value转换为简单类型实例,如果类型不匹配,则直接引起panic
func (v Value) Bool() bool
func (v Value) Float() float64
func (v Value) Int() int64
func (v Value) Uint() uint64
  1. 从Value的指针到值 从一个指针类型的Value获取值类型Value有两种方法,示例如下:
1
2
3
4
5
// 如果v类型是接口,则Elem()返回接口绑定的实例的Value;如果v类型是指针,则返回指针值的Value,否则引起panic
func (v Value) Elem() Value

// 如果v是指针,则返回指针值的Value,否则返回v自身,该函数不会一起panic
func Indirect(v Value) Value
  1. Type指针和值的相互转换 (1) 指针类型Type到值类型Type,例如
1
2
3
// t 必须是Array, Chan, Map, Ptr, Slice, 否则会引起panic
// Elem返回的是其内部元素的Type
t.Elem() Type

(2) 值类型Type到指针类型的Type,例如

1
2
// PtrTo返回的是指向t的指针型Type
func PtrTo(t Type) Type
  1. Value值的可修改性 Value值的修改涉及如下两个方法
1
2
3
4
5
// 通过CanSet判断是否能修改
func (v Value) CanSet() bool

// 通过Set进行修改
func (v Value) Set(x Value)

Value值在什么时候可以修改?我们知道实例对象传递给接口的是一个完全的值拷贝,如果 调用反射的方法reflect.ValueOf()传递去的是一个值类型变量,则获得的Value实际上是 原对象的一个副本,这个Value是无论如何也不能被修改的。如果传递去的是一个指针, 虽然接口内部转换的也是指针的副本,但通过指针还是可以访问到最原始的对象, 所以,此种情况获得的Value是可以修改的。


专题:

本文发表于 2022-09-13,最后修改于 2022-09-13。

本站永久域名「 jiavvc.top 」,也可搜索「 后浪笔记一零二四 」找到我。


上一篇 « 大道至简 下一篇 » Go语言里程碑

赞赏支持

请我吃鸡腿 =^_^=

i ysf

云闪付

i wechat

微信

推荐阅读

Big Image