Golang interface reflection knowledge points

Golang interface reflection knowledge points

This article Go to the official classic blog The Laws of Reflection is based on detailed knowledge involved in the text, and has been expanded.

1. interface type variable

First of all, we talk about the interface type of memory layout (memory layout), other basic types, Struct, Slice, Map, Pointer type of memory layout will be analyzed separately in the future. Variable value of the interface consists of two parts: the interface type assigned to the actual value of the variable (concrete value), type information (type descriptor) of the actual value. The two parts together to form the value of the interface (interface value).

The two parts of the interface variables stored by words (32-bit system is assumed, it is a 32-bit word), pointing to the first word itable (interface table). itable represents the actual type of interface and conversion information. itable is stored at the beginning of a variable actual type description information , followed by a list of function pointers thereof. Note itable Functions and corresponding interface type, and instead of the dynamic type . For example the following example, only the association ITable a String method defined in Stringer, the Get method Binary not defined therein. For each type of interface and practical, as long as the code is present in the reference relationship, for this will Go to a particular <Interface, Type> itable generated at run time.

The second word is called data, the actual data points. Example, assignment var s Stringer = b in fact to make a copy of b rather than referenced b . Interface variables stored in the data may be any size, but the interface provides only one word to specifically store the actual data, so the assignment statement in a block of memory allocated on the heap, and set the word as a reference to this memory .

type Stringer interface {
    String() string
}

type Binary uint64

func (i Binary) String() string {
    return strconv.Uitob64(i.Get(), 2)
}

func (i Binary) Get() uint64 {
    return uint64(i)
}

b := Binary(200)
var s Stringer = b

Golang Memory Interface Layout

Go is a statically typed language (statically typed). A different interface types of variables always have the same static type, although at run time, the actual value will change saved interface variables. In the following examples, r is given regardless of what the actual value, r is always the type io.Reader.

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

2. Type assertion

A type assertion is operating variables used on the interface.

var r io.Reader
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
    return nil, err
}
r = tty

In this example, R & lt tty is given of a copy , so the actual value is tty. The actual type is * os.File. To note, * os.File type itself also implements a method other than the interface method Read. Although the interface variables can only access the Read method, but the data portion of the interface's word carries all the information about the actual value. So we have the following:

var w io.Writer
w = r.(io.Writer)

The assignment is behind a type of assertion. It asserts that carry variable r elements, while achieving io.Writer interface, so that we can put r assigned to w. w After the assignment can access the Write method, but can not access the Read method.

3. Ducks type

Duck typing (duck typing) is an object-type dynamic and some static language used to infer style. A semantic object is active, not inherited from a particular class or implement specific interfaces, but by the "current set of methods and properties." This concept can also be expressed as:

When you see a bird walks like a duck, swim like a duck and quacks like a duck, then this bird can be called a duck.

Ducks like polymorphic type as work, but there is no inheritance. In the duck type, the focus is on the behavior of objects, what can do; rather than on the type of object belongs. In the conventional type, we can use an object in a particular scenario depends on the type of the object, and in the duck type, depends on whether the object has some property or method - that is, provided they have specific properties or a method, by test duck type, can be used. Duck disadvantage is that no static type checking, such as checking the type, property inspection, inspection method signature.

Go though the language is statically typed languages, but uses duck typing interface type. Unlike other duck typed language it is that it implements statically checked at compile time , such as whether a variable implements the interface method, the number of parameters when calling the interface methods are consistent, yet also flexible and liberty of duck typing.

4. reflection

  • What is reflection?

In computer science, reflection refers to the computer program at run time (Run time) can be accessed, the ability to detect and modify its own state or behavior. Metaphorically speaking, when the program is reflected in the running can "observe" and to modify their behavior.

Briefly, reflecting only a mechanism for obtaining object type information and memory structures when the program runs . Usually by means of reflection high-level language to solve, you can not know the specific type of the variable compile-time, but only until runtime to check the value and type of problem. Reflection model are not the same in different languages, some languages do not support reflection. For low-level language, such as assembly language, due to its memory and can deal directly, so no reflection.

  • Use scene reflected?

Go language using reflection scene: sometimes need to decide which function calls under certain conditions, such as to decide based on user input, but does not know in advance what type of parameters received, all to accept the type interface {}. Then you need reflection function parameters, functions performed dynamically during operation. The interested reader may refer fmt.Sprint (a ... interface {}) source method.

5. reflect package

TypeOf()、ValueOf()

reflect package encapsulates a number of simple methods (reflect.TypeOf and reflect.ValueOf) to dynamically obtain information about the type and the actual value (reflect.Type, reflect.Value).

var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))  // 打印 type: float64

var r io.Reader = strings.NewReader("Hello")
fmt.Println("type:", reflect.TypeOf(r))  // 打印 type: *strings.Reader

Reflect.TypeOf function signature process is func TypeOf (i interface {}) Type. It accepts any type of variable. When we call reflect.TypeOf (x), x is first stored in an empty interface type, as the parameter passing. reflect.TypeOf resolve empty interface, the type of recovery information x. The call reflect.ValueOf you can recover the actual value of x.

var x float64 = 3.4
fmt.Println("value:", reflect.ValueOf(x).String()) // 打印 value: <float64 Value>

Type()、Kind()

reflect.Type and reflect.Value provides many ways to support their operations. 1. reflect.Value of the Type () method returns the actual type of information;. 2 reflect.Type and reflect.Value both the Kind () method to obtain the underlying type of the actual value of the result corresponds to reflect package defines constants; in those types of named 3. reflect.Value method name, such as Int (), Float (), to get the actual value.

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

Print Results:

shell script type: float64 kind is float64: true value: 3.4

One thing to note is that, the Kind () method returns the type of the underlying reflecting object, instead of static type . For example, if the reflecting object accepts a user defined integer variables:

func main() {
    type MyInt int
    var x MyInt = 7
    v := reflect.ValueOf(x)
    fmt.Println("type:", v.Type())
    fmt.Println("kind is int:", v.Kind() == reflect.Int)
    fmt.Println("value:", v.Int())
}

Print Results:
shell script type: main.MyInt kind is int: true value: 7

v call Kind () is still reflect.Int, even if the static type of x is MyInt instead of int. In summary, the Kind () method can not distinguish between an int and integer from MyInt, but the Type () methods .

Interface()

Interface () method of recovering from an interface reflect.Value variable value is ValueOf () reverse. Note that, Interface () method returns always static type interface {}.

6 may be provided of the reflecting object

SetXXX(), CanSet()

var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1)  // will panic: reflect.Value.SetFloat using unaddressable value

Running the above example, we can see that v can not be modified (settable). May be disposed of (Settability) reflect.Value is a characteristic of, but not all are Value.

var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("settability of v:", v.CanSet())  // settability of v: false

Element()

Because it is a copy of incoming x reflect.ValueOf, so a copy is created interface value reflect.ValueOf of x, x is not the original itself. Thus modify reflecting object can not be modified x, having no reflecting object may be disposed of.

Clearly, to make the reflecting object has disposed of. The argument should be passed reflect.ValueOf address x, that & x.

var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println("type of p:", p.Type())  // type of p: *float64
fmt.Println("settability of p:", p.CanSet())  // settability of p: false

Reflecting object p is still not set, because we do not want to set p, but p points to the content. Use Elem method to get.

// 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 (v Value) Elem() Value
v := p.Elem()
fmt.Println("settability of v:", v.CanSet())  // settability of v: true

v.SetFloat(7.1)
fmt.Println(v.Interface())  // 7.1
fmt.Println(x)  // 7.1

7. Struct reflection of

NumField(), Type.Field(i int)

We address struct to create a reflecting object, so that we can follow to modify this struct:

type T struct {
    A int
    B string
}

t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()

for i := 0; i < s.NumField(); i++ {
    f := s.Field(i)
    fmt.Printf("%d: %s %s = %v\n", i,
        typeOfT.Field(i).Name, f.Type(), f.Interface())
}

Type.Field (i int) method returns the field information, an object type StructField, contains the field name and the like.

Print Results:

0: A int = 23
1: B string = skidoo

Value.Field(i int)

T fields must be capitalized only be set, because only exposed struct field, it has set up sex .

s.Field(0).SetInt(77)
s.Field(1).SetString("Sunset Strip")
fmt.Println("t is now", t) // t is now {77 Sunset Strip}

Value.Field (i int) returns the actual value of the struct s field, the setting operation can be used. Note Type.Field (i int) and Value.Field (i int) uses the difference between: the former is always responsible for the actual type of information acquired and related operations, which are related to the actual value of the operation .

Reference Documents

The Laws of Reflection

Go Data Structures: Interfaces

Go data structures of language: Interfaces

On Golang Interface implementation principle

Decryption depth reflection of the Go language

Guess you like

Origin www.cnblogs.com/guangze/p/11621277.html