A Brief introduction to Go structure struct interface Interface Reflection
- 2020-06-03 06:53:32
- OfStack
Structure struct
struct USES custom complex data structures that can contain multiple fields (properties) and can be nested.
The struct type in go is understood as a class that defines methods, slightly different from function definitions;
The struct type is a value type.
struct definition
type User struct {
Name string
Age int32
mess string
}
var user User
var user1 *User = &User{}
var user2 *User = new(User)
struct use
In the following example, user1 and user2 are pointer types. When accessed, the compiler automatically converts user1.Name to (*user1).Name
func main() {
var user User
user.Name = "nick"
user.Age = 18
user.mess = "lover"
var user1 *User = &User{
Name: "dawn",
Age: 21,
}
fmt.Println(*user1) //{dawn 21 }
fmt.Println(user1.Name, (*user1).Name) //dawn dawn
var user2 *User = new(User)
user2.Name = "suoning"
user2.Age = 18
fmt.Println(user2) //&{suoning 18 }
fmt.Println(user2.Name, (*user2).Name) //suoning suoning
}
The constructor
struct in golang does not have a constructor, and one can be forged
type User struct {
Name string
Age int32
mess string
}
func NewUser(name string, age int32, mess string) *User {
return &User{Name:name,Age:age,mess:mess}
}
func main() {
//user := new(User)
user := NewUser("suoning", 18, "lover")
fmt.Println(user, user.mess, user.Name, user.Age)
}
Memory layout
All fields in struct are contiguous in memory
var user User
user.Name = "nick"
user.Age = 18
user.mess = "lover"
fmt.Println(user) //{nick 18 lover}
fmt.Printf("Name:%p\n", &user.Name) //Name:0xc420016180
fmt.Printf("Age: %p\n", &user.Age) //Age: 0xc420016190
fmt.Printf("mess:%p\n", &user.mess) //mess:0xc420016198 8 Bytes align memory
methods
Methods are applied to variables of a particular type, so custom types can have methods, not just struct.
Method access control is also case-controlled.
The init function is implemented by passing in a pointer, which changes the value of the struct field because it is a value type.
type User struct {
Name string
Age int
sex string
}
func (this *User) init(name string, age int, sex string) {
this.Name = name
this.Age = age
this.sex = sex
}
func (this User) GetName() string {
return this.Name
}
func main() {
var user User
user.init("nick", 18, "man")
//(&user).init("nick", 18, "man")
name := user.GetName()
fmt.Println(name)
}
Anonymous fields
If there is a conflict, the outermost priority
type User struct {
Name stirng
Age int
}
type Lover struct {
User
sex time.Time
int
Age int
}
inheritance & Multiple inheritance
A struct inherits multiple structs and accesses a passing point. Inherit fields and methods.
You can use aliases such as u1 (user1) below and visit ES69en.u1.Age.
If the inherited structure has the same field, an error will be reported if accessed through ES74en.name and must be accessed through ES76en.user1.name.
type user1 struct {
name string
Age int
}
type user2 struct {
name string
age int
sex time.Time
}
type User struct {
u1 user1 // The alias
user2
Name string
Age int
}
func main() {
var user User
user.Name = "nick"
user.u1.Age = 18
fmt.Println(user) //{{ 18} { 0 {0 0 <nil>}} nick 0}
}
tag
In go, initial case has a special syntactic meaning and cannot be referenced outside of a lowercase package. Due to the need to interact with other systems, such as converting to json format. At this point, if you use the property name as the key value, it may not be 1, which will definitely meet the project requirements. tag USES specific fields as keys when converting to other data formats.
import "encoding/json"
type User struct {
Name string `json:"userName"`
Age int `json:"userAge"`
}
func main() {
var user User
user.Name = "nick"
user.Age = 18
conJson, _ := json.Marshal(user)
fmt.Println(string(conJson)) //{"userName":"nick","userAge":0}
}
String()
If the method String() is implemented, fmt () calls String() by default.
type name1 struct {
int
string
}
func (this *name1) String() string {
return fmt.Sprintf("This is String(%s).", this.string)
}
func main() {
n := new(name1)
fmt.Println(n) //This is String().
n.string = "suoning"
d := fmt.Sprintf("%s", n) //This is String(suoning).
fmt.Println(d)
}
Interface Interface
The Interface type can define a set of methods, but these do not need to be implemented. And interface cannot contain any variables.
The interface type defaults to 1 pointer.
Interface definition
var user User
var user1 *User = &User{}
var user2 *User = new(User)
0
Interface implementation
The interface in Golang does not need to be displayed by the implementation. As long as a variable contains all the methods in the interface type, that variable implements the interface. Therefore, there is no keyword similar to implement in golang;
If a variable contains more than one method of type interface, the variable implements more than one interface. If a variable contains only 1 square method of interface, then the variable does not implement this interface.
Empty interface Interface{} : Empty interfaces have no methods, so all types implement empty interfaces.
var a int
var b interface{} // Empty interface
b = a
polymorphism
Various forms of one kind of thing can be operated according to the interface of Unity 1.
Chestnut:
type Car interface {
NameGet() string
Run(n int)
Stop()
}
type BMW struct {
Name string
}
func (this *BMW) NameGet() string {
return this.Name
}
func (this *BMW) Run(n int) {
fmt.Printf("BMW is running of num is %d \n", n)
}
func (this *BMW) Stop() {
fmt.Printf("BMW is stop \n")
}
type Benz struct {
Name string
}
func (this *Benz) NameGet() string {
return this.Name
}
func (this *Benz) Run(n int) {
fmt.Printf("Benz is running of num is %d \n", n)
}
func (this *Benz) Stop() {
fmt.Printf("Benz is stop \n")
}
func (this *Benz) ChatUp() {
fmt.Printf("ChatUp \n")
}
func main() {
var car Car
fmt.Println(car) // <nil>
var bmw BMW = BMW{Name: " BMW "}
car = &bmw
fmt.Println(car.NameGet()) // BMW
car.Run(1) //BMW is running of num is 1
car.Stop() //BMW is stop
benz := &Benz{Name: " Big rush "}
car = benz
fmt.Println(car.NameGet()) // Big rush
car.Run(2) //Benz is running of num is 2
car.Stop() //Benz is stop
//car.ChatUp() //ERROR: car.ChatUp undefined (type Car has no field or method ChatUp)
}
Interface nested
1 interface can be nested in another interface.
That is, a method that needs to implement two interfaces.
var user User
var user1 *User = &User{}
var user2 *User = new(User)
3
Types of assertions
Type assertion, because the interface is 1 generic, and the specific type is unknown,
If you want to convert to a specific type, you can do so by:
var user User
var user1 *User = &User{}
var user2 *User = new(User)
4
Chestnut 1:
var user User
var user1 *User = &User{}
var user2 *User = new(User)
5
Chestnut 2:
var user User
var user1 *User = &User{}
var user2 *User = new(User)
6
Chestnut 3:
Determines whether a variable implements the specified interface
type Stringer interface {
String() string
}
type Mystruct interface {
}
type Mystruct2 struct {
}
func (this *Mystruct2) String() string {
return ""
}
func main() {
var v Mystruct
var v2 Mystruct2
v = &v2
if sv, ok := v.(Stringer); ok {
fmt.Printf("%v implements String(): %s\n", sv.String());
}
}
Reflection reflect
The reflect package implements runtime reflection, allowing programs to manipulate objects of any type.
Typical usage is to store 1 value with static type interface{},
This function returns a value of type Type by calling TypeOf to get its dynamic type information.
A call to the ValueOf function returns a value of type Value, which represents the data at run time.
func TypeOf(i interface{}) Type
TypeOf returns the type of value saved in the interface, and TypeOf(nil) returns nil.
func ValueOf(i interface{}) Value
ValueOf returns 1 Value initialized to the specific value held by the i interface, and ValueOf(nil) returns Value zero.
reflect.Value.Kind
Gets the category of the variable, returning 1 constant
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
)
reflect.Value.Kind() The constant returned by the
reflect.Value.Interface()
Cast to type interface{}
The variable < -- > Interface{} < -- > Reflect. Value 】
Get the value of the variable:
var user User
var user1 *User = &User{}
var user2 *User = new(User)
9
To change the value of a variable by reflecting it
reflect.Value.SetXX Related methods, such as :
reflect.Value.SetInt() , set the integer
reflect.Value.SetFloat() , set the floating-point number
reflect.Value.SetString() , set the string
Chestnut 1
import "reflect"
func main() {
var x float64 = 5.21
fmt.Println("type:", reflect.TypeOf(x)) //type: float64
v := reflect.ValueOf(x)
fmt.Println("value:", v) //value: 5.21
fmt.Println("type:", v.Type()) //type: float64
fmt.Println("kind:", v.Kind()) //kind: float64
fmt.Println("value:", v.Float()) //value: 5.21
fmt.Println(v.Interface()) //5.21
fmt.Printf("value is %1.1e\n", v.Interface()) //value is 5.2e+00
y := v.Interface().(float64)
fmt.Println(y) //5.21
}
Chestnut 2 (Modified value)
SetXX(x) since it is passing a copy of the value of x, SetXX cannot change x. Changing x must pass a pointer to x to the function, SetXX( & x).
// Error code!!
//panic: reflect: reflect.Value.SetFloat using unaddressable value
func main() {
var a float64
fv := reflect.ValueOf(&a)
fv.SetFloat(520.00)
fmt.Printf("%v\n", a)
}
// Correct, pass pointer
func main() {
var a2 float64
fv2 := reflect.ValueOf(&a2)
fv2.Elem().SetFloat(520.00)
fmt.Printf("%v\n", a2) //520
}
Reflection operating structure
reflect. Value. NumField() gets the number of fields in the structure
reflect.Value.Method (n).Call (nil) to invoke methods in the structure
Chestnut 1 (Operating the structure by reflection)
import "reflect"
type NotknownType struct {
S1 string
S2 string
S3 string
}
func (n NotknownType) String() string {
return n.S1 + " & " + n.S2 + " & " + n.S3
}
var secret interface{} = NotknownType{"Go", "C", "Python"}
func main() {
value := reflect.ValueOf(secret)
fmt.Println(value) //Go & C & Python
typ := reflect.TypeOf(secret)
fmt.Println(typ) //main.NotknownType
knd := value.Kind()
fmt.Println(knd) // struct
for i := 0; i < value.NumField(); i++ {
fmt.Printf("Field %d: %v\n", i, value.Field(i))
}
results := value.Method(0).Call(nil)
fmt.Println(results) // [Go & C & Python]
}
Chestnut 2 (Modifying the structure by reflection)
import "reflect"
type T struct {
A int
B string
}
func main() {
t := T{18, "nick"}
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())
}
s.Field(0).SetInt(25)
s.Field(1).SetString("nicky")
fmt.Println(t)
}
/*
Output:
0: A int = 18
1: B string = nick
{25 nicky}
*/
import "reflect"
type test struct {
S1 string
s2 string
s3 string
}
var s interface{} = &test{
S1: "s1",
s2: "s2",
s3: "s3",
}
func main() {
val := reflect.ValueOf(s)
fmt.Println(val) //&{s1 s2 s3}
fmt.Println(val.Elem()) //{s1 s2 s3}
fmt.Println(val.Elem().Field(0)) //s1
val.Elem().Field(0).SetString("hehe") //S1 A capital
}
Chestnut 3 (internal implementation of struct tag)
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string `json:"user_name"`
}
func main() {
var user User
userType := reflect.TypeOf(user)
jsonString := userType.Field(0).Tag.Get("json")
fmt.Println(jsonString) //user_name
}