ReflectBase

ReflectBase

overview

Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types. The typical use is to take a value with static type interface{} and extract its dynamic type information by calling TypeOf, which returns a Type.

A call to ValueOf returns a Value representing the run-time data. Zero takes a Type and returns a Value representing a zero value for that type.

包反射实现了运行时反射,允许程序操作任意类型的对象。典型的用法是获取一个具有静态类型接口{}的值,并通过调用TypeOf来提取其动态类型信息,后者将返回一个类型。

func Copy

func Copy(dst, src Value) int

Copy copies the contents of src into dst until either dst has been filled or src has been exhausted. It returns the number of elements copied. Dst and src each must have kind Slice or Array, and dst and src must have the same element type.

As a special case, src can have kind String if the element type of dst is kind Uint8.

Copy将src的内容复制到dst中,直到dst已填满或src已用完。它返回复制的元素的数量。Dst和src必须分别具有类片或数组,Dst和src必须具有相同的元素类型。

作为一种特殊情况,如果dst的元素类型是kind Uint8,那么src可以使用kind字符串。

拷贝到特定大小的dst

dst留出位置<len(src)

package main

import "fmt"

func main() {
	dst := []int{1, 2, 3, 4, 5, 6}
	src := []int{7, 8, 9, 10}
	copy(dst[2:4], src)
	fmt.Println("dst:", dst)
	fmt.Println("src:", src)
}

## 输出
dst: [1 2 7 8 5 6]
src: [7 8 9 10]

dst留出位置>len(src)

package main

import "fmt"

func main() {
	dst := []int{1, 2, 3, 4, 5, 6}
	src := []int{7}
	copy(dst[2:4], src)
	fmt.Println("dst:", dst)
	fmt.Println("src:", src)
}


## 输出
dst: [1 2 7 4 5 6]
src: [7]

拷贝[2:]这种的

dst留出位置<len(src)

package main

import "fmt"

func main() {
	dst := []int{1, 2, }
	src := []int{7, 8, 9, 10}
	copy(dst[0:], src)
	fmt.Println("dst:", dst)
	fmt.Println("src:", src)
}

## 输出
dst: [7 8]
src: [7 8 9 10]

dst留出位置>len(src)

package main

import "fmt"

func main() {
	dst := []int{1, 2, 3, 4, 5, 6}
	src := []int{7}
	copy(dst[2:], src)
	fmt.Println("dst:", dst)
	fmt.Println("src:", src)
}

## 输出
dst: [1 2 7 4 5 6]
src: [7]

copy小结

复制的只是dst空间大小

func DeepEqual

func DeepEqual(x, y interface{}) bool

Array values are deeply equal when their corresponding elements are deeply equal.

Struct values are deeply equal if their corresponding fields, both exported and unexported, are deeply equal.

Func values are deeply equal if both are nil; otherwise they are not deeply equal.

Interface values are deeply equal if they hold deeply equal concrete values.

Map values are deeply equal when all of the following are true: they are both nil or both non-nil, they have the same length, and either they are the same map object or their corresponding keys (matched using Go equality) map to deeply equal values.

Pointer values are deeply equal if they are equal using Go's == operator or if they point to deeply equal values.

Slice values are deeply equal when all of the following are true: they are both nil or both non-nil, they have the same length, and either they point to the same initial entry of the same underlying array (that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal. Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil)) are not deeply equal.

Other values - numbers, bools, strings, and channels - are deeply equal if they are equal using Go's == operator.

In general DeepEqual is a recursive relaxation of Go's == operator. However, this idea is impossible to implement without some inconsistency. Specifically, it is possible for a value to be unequal to itself, either because it is of func type (uncomparable in general) or because it is a floating-point NaN value (not equal to itself in floating-point comparison), or because it is an array, struct, or interface containing such a value. On the other hand, pointer values are always equal to themselves, even if they point at or contain such problematic values, because they compare equal using Go's == operator, and that is a sufficient condition to be deeply equal, regardless of content. DeepEqual has been defined so that the same short-cut applies to slices and maps: if x and y are the same slice or the same map, they are deeply equal regardless of content.

As DeepEqual traverses the data values it may find a cycle. The second and subsequent times that DeepEqual compares two pointer values that have been compared before, it treats the values as equal rather than examining the values to which they point. This ensures that DeepEqual terminates.

DeepEqual报告x和y是否“深度相等”,定义如下。如果满足以下情况之一,则两个相同类型的值将非常相等。不同类型的值永远不会完全相等。

当数组的对应元素深度相等时,数组值深度相等。

如果结构的值对应的字段(导出和未导出)都非常相等,则它们非常相等。

如果两者均为零,则Func值非常相等。否则,它们就不会完全平等。

如果接口值具有完全相等的具体值,则它们是高度相等的。

当满足以下所有条件时,映射值深度相等:它们都为nil或都不为nil,它们的长度相同,并且它们是相同的映射对象或它们的对应键(使用Go相等匹配)映射到相等的值。

如果指针值使用Go's ==运算符相等,或者它们指向深度相等的值,则它们的深度相等。

当满足以下所有条件时,切片值将完全相等:它们均为nil或均为非nil,它们具有相同的长度,并且它们指向同一基础数组的相同初始条目(即&x [0 ] ==&y [0])或它们相应的元素(最大长度)相等。请注意,非nil空片和nil片(例如[] byte {}和[] byte(nil))并不完全相等。

如果使用Go的==运算符,其他值(数字,布尔值,字符串和通道)将完全相等。

通常,DeepEqual是Go的运算符的递归松弛。但是,如果没有一些不一致,就不可能实现这个想法。具体来说,可能是因为值属于func类型(通常无法比较)或因为它是浮点NaN值(在浮点比较中不等于其自身),或者因为它是包含此类值的数组,结构或接口。另一方面,指针值即使指向或包含此类有问题的值也始终等于其自身,因为它们使用Go的运算符进行相等比较,而这足以使深度相等,而与内容无关。已定义DeepEqual,以便将相同的快捷方式应用于切片和贴图:如果x和y是相同的切片或相同的贴图,

当DeepEqual遍历数据值时,可能会发现一个循环。DeepEqual在第二次及以后比较两个之前比较过的指针值时,会将这些值视为相等,而不是检查它们所指向的值。这样可以确保DeepEqual终止。

func Swapper1.8

func Swapper(slice interface{}) func(i, j int)

Swapper returns a function that swaps the elements in the provided slice.

Swapper panics if the provided interface is not a slice.

Swapper返回一个函数,该函数交换提供的片中的元素。

如果提供的接口不是切片,则交换器会出现混乱。

package main

import (
	"fmt"
	"reflect"
)

func main() {
	s := []int{1, 2, 3, 4, 5, 6}
	swapper := reflect.Swapper(s)
	swapper(0, 1)
	fmt.Println(s)
}

## 输出
[2 1 3 4 5 6]

type ChanDir

ChanDir represents a channel type's direction.

type ChanDir int
const (
    RecvDir ChanDir             = 1 << iota // <-chan
    SendDir                                 // chan<-
    BothDir = RecvDir | SendDir             // chan
)

func (ChanDir) String

func (d ChanDir) String() string

type Kind

A Kind represents the specific kind of type that a Type represents. The zero Kind is not a valid kind.

type Kind uint
const (
    Invalid Kind = iota
    Bool
    Int
    Int8
    Int16
    Int32
    Int64
    Uint
    Uint8
    Uint16
    Uint32
    Uint64
    Uintptr
    Float32
    Float64
    Complex64
    Complex128
    Array
    Chan
    Func
    Interface
    Map
    Ptr
    Slice
    String
    Struct
    UnsafePointer
)
package main

import (
	"fmt"
	"reflect"
)

func main() {
	for _, v := range []interface{}{"hi", 42, func() {}} {
		switch v := reflect.ValueOf(v); v.Kind() {
		case reflect.String:
			fmt.Println(v.String())
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			fmt.Println(v.Int())
		default:
			fmt.Printf("unhandled kind %s", v.Kind())
		}
	}

}

## 输出
hi
42
unhandled kind func

func (Kind) String

func (k Kind) String() string

String returns the name of k.

type MapIter1.12

A MapIter is an iterator for ranging over a map. See Value.MapRange.

type MapIter struct {
    // contains filtered or unexported fields
}

func (*MapIter) Key1.12

func (it *MapIter) Key() Value

Key returns the key of the iterator's current map entry.

func (*MapIter) Next1.12

func (it *MapIter) Next() bool

Next advances the map iterator and reports whether there is another entry. It returns false when the iterator is exhausted; subsequent calls to Key, Value, or Next will panic.

func (*MapIter) Value1.12

func (it *MapIter) Value() Value

Value returns the value of the iterator's current map entry.

type Method

Method represents a single method.

type Method struct {
    // Name is the method name.
    // PkgPath is the package path that qualifies a lower case (unexported)
    // method name. It is empty for upper case (exported) method names.
    // The combination of PkgPath and Name uniquely identifies a method
    // in a method set.
    // See https://golang.org/ref/spec#Uniqueness_of_identifiers
    Name    string
    PkgPath string

    Type  Type  // method type
    Func  Value // func with receiver as first argument
    Index int   // index for Type.Method
}

type StructField

A StructField describes a single field in a struct.

type StructField struct {
    // Name is the field name.
    Name string
    // PkgPath is the package path that qualifies a lower case (unexported)
    // field name. It is empty for upper case (exported) field names.
    // See https://golang.org/ref/spec#Uniqueness_of_identifiers
    PkgPath string

    Type      Type      // field type
    Tag       StructTag // field tag string
    Offset    uintptr   // offset within struct, in bytes
    Index     []int     // index sequence for Type.FieldByIndex
    Anonymous bool      // is an embedded field
}

type StructTag

A StructTag is the tag string in a struct field.

By convention, tag strings are a concatenation of optionally space-separated key:"value" pairs. Each key is a non-empty string consisting of non-control characters other than space (U+0020 ' '), quote (U+0022 '"'), and colon (U+003A '😂. Each value is quoted using U+0022 '"' characters and Go string literal syntax.

StructTag是struct字段中的标签字符串。

按照惯例,标签字符串是由空格分隔的键:“值”对的串联。每个键都是一个非空字符串,由非控制字符组成,除了空格(U + 0020''),引号(U + 0022'“')和冒号(U + 003A':')。每个值都用引号引起来使用U + 0022'“'字符和Go字符串文字语法。

type StructTag string

example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	type S struct {
		F string `species:"gopher" color:"blue"`
	}

	s := S{}
	st := reflect.TypeOf(s)
	field := st.Field(0)
	fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"))

}

## res
blue gopher

func (StructTag) Get

func (tag StructTag) Get(key string) string

Get returns the value associated with key in the tag string. If there is no such key in the tag, Get returns the empty string. If the tag does not have the conventional format, the value returned by Get is unspecified. To determine whether a tag is explicitly set to the empty string, use Lookup.

Get返回与标签字符串中的key关联的值。如果标签中没有这样的键,则Get返回空字符串。如果标签没有常规格式,则未指定Get返回的值。若要确定是否将标记明确设置为空字符串,请使用Lookup。

func (StructTag) Lookup1.7

func (tag StructTag) Lookup(key string) (value string, ok bool)

Lookup returns the value associated with key in the tag string. If the key is present in the tag the value (which may be empty) is returned. Otherwise the returned value will be the empty string. The ok return value reports whether the value was explicitly set in the tag string. If the tag does not have the conventional format, the value returned by Lookup is unspecified.

查找返回与标签字符串中的键关联的值。如果密钥存在于标签中,则返回值(可能为空)。否则,返回值将为空字符串。ok返回值报告该值是否在标记字符串中显式设置。如果标记不具有常规格式,则未指定Lookup返回的值。

example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	type S struct {
		F0 string `alias:"field_0"`
		F1 string `alias:""`
		F2 string
	}

	s := S{}
	st := reflect.TypeOf(s)
	for i := 0; i < st.NumField(); i++ {
		field := st.Field(i)
		if alias, ok := field.Tag.Lookup("alias"); ok {
			if alias == "" {
				fmt.Println("(blank)")
			} else {
				fmt.Println(alias)
			}
		} else {
			fmt.Println("(not specified)")
		}
	}

}


## res
field_0
(blank)
(not specified)

type Type1.4

Type is the representation of a Go type.

Not all methods apply to all kinds of types. Restrictions, if any, are noted in the documentation for each method. Use the Kind method to find out the kind of type before calling kind-specific methods. Calling a method inappropriate to the kind of type causes a run-time panic.

Type values are comparable, such as with the == operator, so they can be used as map keys. Two Type values are equal if they represent identical types.

Type是Go类型的表示。

并非所有方法都适用于所有类型。在每种方法的文档中都注明了限制(如果有)。在调用特定于种类的方法之前,请使用Kind方法找出类型。调用不适合该类型的方法会导致运行时恐慌。

类型值是可比较的,例如==运算符,因此它们可用作映射键。如果两个Type值表示相同的类型,则它们相等。

type Type interface {

    // Align returns the alignment in bytes of a value of
    // this type when allocated in memory.
    Align() int

    // FieldAlign returns the alignment in bytes of a value of
    // this type when used as a field in a struct.
    FieldAlign() int

    // Method returns the i'th method in the type's method set.
    // It panics if i is not in the range [0, NumMethod()).
    //
    // For a non-interface type T or *T, the returned Method's Type and Func
    // fields describe a function whose first argument is the receiver.
    //
    // For an interface type, the returned Method's Type field gives the
    // method signature, without a receiver, and the Func field is nil.
    //
    // Only exported methods are accessible and they are sorted in
    // lexicographic order.
    Method(int) Method

    // MethodByName returns the method with that name in the type's
    // method set and a boolean indicating if the method was found.
    //
    // For a non-interface type T or *T, the returned Method's Type and Func
    // fields describe a function whose first argument is the receiver.
    //
    // For an interface type, the returned Method's Type field gives the
    // method signature, without a receiver, and the Func field is nil.
    MethodByName(string) (Method, bool)

    // NumMethod returns the number of exported methods in the type's method set.
    NumMethod() int

    // Name returns the type's name within its package for a defined type.
    // For other (non-defined) types it returns the empty string.
    Name() string

    // PkgPath returns a defined type's package path, that is, the import path
    // that uniquely identifies the package, such as "encoding/base64".
    // If the type was predeclared (string, error) or not defined (*T, struct{},
    // []int, or A where A is an alias for a non-defined type), the package path
    // will be the empty string.
    PkgPath() string

    // Size returns the number of bytes needed to store
    // a value of the given type; it is analogous to unsafe.Sizeof.
    Size() uintptr

    // String returns a string representation of the type.
    // The string representation may use shortened package names
    // (e.g., base64 instead of "encoding/base64") and is not
    // guaranteed to be unique among types. To test for type identity,
    // compare the Types directly.
    String() string

    // Kind returns the specific kind of this type.
    Kind() Kind

    // Implements reports whether the type implements the interface type u.
    Implements(u Type) bool

    // AssignableTo reports whether a value of the type is assignable to type u.
    AssignableTo(u Type) bool

    // ConvertibleTo reports whether a value of the type is convertible to type u.
    ConvertibleTo(u Type) bool

    // Comparable reports whether values of this type are comparable.
    Comparable() bool

    // Bits returns the size of the type in bits.
    // It panics if the type's Kind is not one of the
    // sized or unsized Int, Uint, Float, or Complex kinds.
    Bits() int

    // ChanDir returns a channel type's direction.
    // It panics if the type's Kind is not Chan.
    ChanDir() ChanDir

    // IsVariadic reports whether a function type's final input parameter
    // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
    // implicit actual type []T.
    //
    // For concreteness, if t represents func(x int, y ... float64), then
    //
    //	t.NumIn() == 2
    //	t.In(0) is the reflect.Type for "int"
    //	t.In(1) is the reflect.Type for "[]float64"
    //	t.IsVariadic() == true
    //
    // IsVariadic panics if the type's Kind is not Func.
    IsVariadic() bool

    // Elem returns a type's element type.
    // It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
    Elem() Type

    // Field returns a struct type's i'th field.
    // It panics if the type's Kind is not Struct.
    // It panics if i is not in the range [0, NumField()).
    Field(i int) StructField

    // FieldByIndex returns the nested field corresponding
    // to the index sequence. It is equivalent to calling Field
    // successively for each index i.
    // It panics if the type's Kind is not Struct.
    FieldByIndex(index []int) StructField

    // FieldByName returns the struct field with the given name
    // and a boolean indicating if the field was found.
    FieldByName(name string) (StructField, bool)

    // FieldByNameFunc returns the struct field with a name
    // that satisfies the match function and a boolean indicating if
    // the field was found.
    //
    // FieldByNameFunc considers the fields in the struct itself
    // and then the fields in any embedded structs, in breadth first order,
    // stopping at the shallowest nesting depth containing one or more
    // fields satisfying the match function. If multiple fields at that depth
    // satisfy the match function, they cancel each other
    // and FieldByNameFunc returns no match.
    // This behavior mirrors Go's handling of name lookup in
    // structs containing embedded fields.
    FieldByNameFunc(match func(string) bool) (StructField, bool)

    // In returns the type of a function type's i'th input parameter.
    // It panics if the type's Kind is not Func.
    // It panics if i is not in the range [0, NumIn()).
    In(i int) Type

    // Key returns a map type's key type.
    // It panics if the type's Kind is not Map.
    Key() Type

    // Len returns an array type's length.
    // It panics if the type's Kind is not Array.
    Len() int

    // NumField returns a struct type's field count.
    // It panics if the type's Kind is not Struct.
    NumField() int

    // NumIn returns a function type's input parameter count.
    // It panics if the type's Kind is not Func.
    NumIn() int

    // NumOut returns a function type's output parameter count.
    // It panics if the type's Kind is not Func.
    NumOut() int

    // Out returns the type of a function type's i'th output parameter.
    // It panics if the type's Kind is not Func.
    // It panics if i is not in the range [0, NumOut()).
    Out(i int) Type
    // contains filtered or unexported methods
}

func (Value) Elem

func (v Value) Elem() Value

Elem returns the value that the interface v contains or that the pointer v points to. It panics if v's Kind is not Interface or Ptr. It returns the zero Value if v is nil.

func (Value) Field

func (v Value) Field(i int) Value

Field returns the i'th field of the struct v. It panics if v's Kind is not Struct or i is out of range.

func (Value) FieldByIndex

func (v Value) FieldByIndex(index []int) Value

FieldByIndex returns the nested field corresponding to index. It panics if v's Kind is not struct.

func (Value) FieldByName

func (v Value) FieldByName(name string) Value

FieldByName returns the struct field with the given name. It returns the zero Value if no field was found. It panics if v's Kind is not struct.

func (Value) MapRange1.12

func (v Value) MapRange() *MapIter

MapRange returns a range iterator for a map. It panics if v's Kind is not Map.

Call Next to advance the iterator, and Key/Value to access each entry. Next returns false when the iterator is exhausted. MapRange follows the same iteration semantics as a range statement.

Example:

iter := reflect.ValueOf(m).MapRange()
for iter.Next() {
	k := iter.Key()
	v := iter.Value()
	...
}

func (Value) Pointer

func (v Value) Pointer() uintptr

Pointer returns v's value as a uintptr. It returns uintptr instead of unsafe.Pointer so that code using reflect cannot obtain unsafe.Pointers without importing the unsafe package explicitly. It panics if v's Kind is not Chan, Func, Map, Ptr, Slice, or UnsafePointer.

If v's Kind is Func, the returned pointer is an underlying code pointer, but not necessarily enough to identify a single function uniquely. The only guarantee is that the result is zero if and only if v is a nil func Value.

If v's Kind is Slice, the returned pointer is to the first element of the slice. If the slice is nil the returned value is 0. If the slice is empty but non-nil the return value is non-zero.

指针将v的值作为uintptr返回。它返回uintptr而不是unsafe.Pointer,因此使用反射的代码无法在不显式导入不安全包的情况下获取不安全。如果v的Kind不是Chan,Func,Map,Ptr,Slice或UnsafePointer,它将惊慌。

如果v的Kind为Func,则返回的指针是基础代码指针,但不一定足以唯一地标识单个函数。唯一的保证是,当且仅当v为nil func值时,结果为零。

如果v的Kind为Slice,则返回的指针指向该切片的第一个元素。如果切片为nil,则返回值为0。如果切片为空但非nil,则返回值为非零。

几个重要例子

kind

package main

import (
	"fmt"
	"reflect"
)

func main() {
	for _, v := range []interface{}{"hi", 42, func() {}} {
		switch v := reflect.ValueOf(v); v.Kind() {
		case reflect.String:
			fmt.Println(v.String())
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			fmt.Println(v.Int())
		default:
			fmt.Printf("unhandled kind %s", v.Kind())
		}
	}

}

## res
hi
42
unhandled kind func

StructOf

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
)

func main() {
	typ := reflect.StructOf([]reflect.StructField{
		{
			Name: "Height",
			Type: reflect.TypeOf(float64(0)),
			Tag:  `json:"height"`,
		},
		{
			Name: "Age",
			Type: reflect.TypeOf(int(0)),
			Tag:  `json:"age"`,
		},
	})

	v := reflect.New(typ).Elem()
	v.Field(0).SetFloat(0.4)
	v.Field(1).SetInt(2)
	s := v.Addr().Interface()

	w := new(bytes.Buffer)
	if err := json.NewEncoder(w).Encode(s); err != nil {
		panic(err)
	}

	fmt.Printf("value: %+v\n", s)
	fmt.Printf("json:  %s", w.Bytes())

	r := bytes.NewReader([]byte(`{"height":1.5,"age":10}`))
	if err := json.NewDecoder(r).Decode(s); err != nil {
		panic(err)
	}
	fmt.Printf("value: %+v\n", s)

}

## res
value: &{Height:0.4 Age:2}
json:  {"height":0.4,"age":2}
value: &{Height:1.5 Age:10}

StructTag

package main

import (
	"fmt"
	"reflect"
)

func main() {
	type S struct {
		F string `species:"gopher" color:"blue"`
	}

	s := S{}
	st := reflect.TypeOf(s)
	field := st.Field(0)
	fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"))

}

## res
blue gopher

TypeOf

package main

import (
	"fmt"
	"io"
	"os"
	"reflect"
)

func main() {
	// As interface types are only used for static typing, a
	// common idiom to find the reflection Type for an interface
	// type Foo is to use a *Foo value.
	writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()

	fileType := reflect.TypeOf((*os.File)(nil))
	fmt.Println(fileType.Implements(writerType))

}

## res
true
posted @ 2020-12-10 22:53  maob  阅读(83)  评论(0编辑  收藏  举报