golang反射三定律

golang反射三定律

1. 概述

golang的反射能够获取对象属性列表,对象函数列表,函数参数列表,并能够给它们尽心赋值和调用。

2. 类型理解

GO是静态类型的语言。每个变量都有一个静态类型,并且必须在编译之前就已经固定住。

2.1. 静态类型

type MyInt int

var i int
var j MyInt

如果两个变量具有不同的类型,即使底层类型相同,在不经过转换是不能进行相互赋值的。

2.2. interface类型

interface类型能够保存任何具体类型(非interface)的值。例如:

// Reader is the interface that wraps the basic Read method.
type Reader interface {
    Read(p []byte) (n int, err error)
}

// Writer is the interface that wraps the basic Write method.
type Writer interface {
    Write(p []byte) (n int, err error)
}

任何实现Read(Write)方法的类型都是io.Reader(io.Writer)的实现。io.Reader可以保存具有Read方法的任何值。

var r io.Reader
r = os.Stdin
r = bufio.NewReader(r)
r = new(bytes.Buffer)
// and so on

注意:r的类型始终是io.Reader。

2.3. interface{}

空接口interface{}可以为任何值。虽然存储值的类型可能会变,单它也是静态类型。

2.4 变量的表示

  • 变量包含两部分:(value, type)
  • type包含: static type, concrete type
    static type: int, string,
    concrete type: runtime识别的类型
  • 类型断言是否成功,取决于concrete type

3. 反射定律

3.1. 第一定律

反射从接口值到反射对象

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var x float64 = 3.4
    fmt.Println("type:", reflect.TypeOf(x))
    fmt.Println("value:", reflect.ValueOf(x).String())
    v := reflect.ValueOf(x)
    fmt.Println("type:", v.Type())
    fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
    fmt.Println("value:", v.Float())
}

output:

type: float64
value: <float64 Value>
type: float64
kind is float64: true
value: 3.4

3.2. 第二定律

反射从反射对象到接口值

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var x float64 = 3.4
    fmt.Println("type:", reflect.TypeOf(x))
    fmt.Println("value:", reflect.ValueOf(x).String())
    v := reflect.ValueOf(x)
    fmt.Println("type:", v.Type())
    fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
    fmt.Println("value:", v.Float())

    fmt.Println("-----------")
    fmt.Printf("value is %7.1e\n", v.Interface())
}

output:
```bash
type: float64
value:
type: float64
kind is float64: true
value: 3.4

value is 3.4e+00


### 3.3. 第三定律
**要修改反射对象,该值必须可设置**
`v := reflect.ValueOf(x)`是获取x的副本,所以无法直接通过v对x赋值。
```go
package main

import (
    "fmt"
    "reflect"
)

func main() {
    var x float64 = 3.4
    v := reflect.ValueOf(x)
    fmt.Println("type of v:", v.Type())
    fmt.Println("settability of v:", v.CanSet())
    p := reflect.ValueOf(&x)
    fmt.Println("type of p:", p.Type())
    fmt.Println("settability of p.Elem:", p.Elem().CanSet())
}

output:

type of v: float64
settability of v: false
type of p: *float64
settability of p.Elem: true

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 wind.kaisa@gmail.com

💰

×

Help us with donation