kaisawind's blog
  • 关于
  • 所有帖子

golang反射三定律 - Fri, Sep 25, 2020

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:

type: float64
value: <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赋值。

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


辽ICP备2021007608号 | © 2025 | kaisawind

Facebook Twitter GitHub

▄