Go basis of language structure

Go language has no concept of "class" does not support the "class" of inheritance and other object-oriented concepts. Go coupled with the interface language of object-oriented higher than the expandability and flexibility through the embedded structure.

Type alias, and custom types

Custom Types

There are some basic data types, such as the Go language string, 整型, 浮点型, 布尔and other data types, you can use the Go language typekeyword to define a custom type.

Custom type is to define a new type. We can be defined based on the built-in basic types can also be defined by struct. E.g:

//将MyInt定义为int类型
type MyInt int

By Typedefinition of the keyword, MyIntit is a new type that has intproperties.

Type alias

Type alias is Go1.9the new version features added.

Type alias provisions: TypeAlias ​​only Type an alias, in essence, TypeAlias ​​and Type are the same type. Like a child has a child nickname, pet name, the scientific name for school, English teacher and give him the English name, but these names all refer to him personally.

type TypeAlias = Type

We've seen before rune, and byteis the type alias, they are defined as follows:

type byte = uint8
type rune = int32

The difference between type definitions and type aliases

Type alias type definition is only one difference between the surface of the equal sign, we have to understand the difference between them by following the code.

//类型定义
type NewInt int

//类型别名
type MyInt = int

func main() {
    var a NewInt
    var b MyInt
    
    fmt.Printf("type of a:%T\n", a) //type of a:main.NewInt
    fmt.Printf("type of b:%T\n", b) //type of b:int
}

The results show that the type is a main.NewIntshowing of the main package defined NewInttype. b type is int. MyIntType in the code will only exist when there is not compiled MyInttypes.

Structure

Go underlying data type can be expressed in the language of some basic properties of things, but when we want to express all or part of a property of things, then this time the single basic data types obviously can not meet the demand, Go language provides a kinds of custom data types, can encapsulate a plurality of basic data types, data type called this structure, the English name struct. That is, we can structdefine your own type of.

Go through language structto implement object-oriented.

The definition of the structure

Use typeand structkeyword to define the structure, the specific code format is as follows:

type 类型名 struct {
    字段名 字段类型
    字段名 字段类型
    …
}

among them:

  • Name Type: identifies the name of the custom structure, can not be repeated in the same package.
  • Field Name: Indicates the structure field name. Struct field names must be unique.
  • Field Type: indicates the type of the specific structure of the field.

For example, we define a Person(human) body structure, as follows:

type person struct {
    name string
    city string
    age  int8
}

The same type of field can also be written on one line,

type person1 struct {
    name, city string
    age        int8
}

So we have a personcustom type, it has name, city, agethree fields, respectively name, city and age. We use this personstructure can easily represent and store personal information in the program.

Built into the language used to describe the basic data type is a value, and the structure is used to describe a set of values. For example, a person has a name, age and city of residence, etc., it is essentially a polymeric type of data

Examples of structure

Only when the structure is instantiated, it will actually allocate memory. That is, the field must be instantiated in order to use the structure.

Itself is a type of structure, we can use the built-in types like declare varkeyword to declare a structure type.

var 结构体实例 结构体类型

The basic instantiation

for example:

type person struct {
    name string
    city string
    age  int8
}

func main() {
    var p1 person
    p1.name = "沙河娜扎"
    p1.city = "北京"
    p1.age = 18
    fmt.Printf("p1=%v\n", p1)  //p1={沙河娜扎 北京 18}
    fmt.Printf("p1=%#v\n", p1) //p1=main.person{name:"沙河娜扎", city:"北京", age:18}
}

We .fields (member variables) to access structure, for example, p1.nameand p1.ageso on.

Anonymous structure

In the definition of some temporary data structures, etc. may also be used anonymously scene structure.

package main
     
import (
    "fmt"
)
     
func main() {
    var user struct{Name string; Age int}
    user.Name = "小王子"
    user.Age = 18
    fmt.Printf("%#v\n", user)
}

Create a pointer type structure

We can also use newinstantiated keyword structure, get the address of the structure. Format is as follows:

var p2 = new(person)
fmt.Printf("%T\n", p2)     //*main.person
fmt.Printf("p2=%#v\n", p2) //p2=&main.person{name:"", city:"", age:0}

From the result we can see that the printed p2a structure pointer.

Note that the support structure pointer directly in the Go language .to member access structure.

var p2 = new(person)
p2.name = "小王子"
p2.age = 28
p2.city = "上海"
fmt.Printf("p2=%#v\n", p2) //p2=&main.person{name:"小王子", city:"上海", age:28}

Taking the address structure of the instantiated

Use &of the body structure fetch address operation is equivalent to a type of the structural newexample of operation.

p3 := &person{}
fmt.Printf("%T\n", p3)     //*main.person
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"", city:"", age:0}
p3.name = "七米"
p3.age = 30
p3.city = "成都"
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"七米", city:"成都", age:30}

p3.name = "七米"In fact, the bottom is (*p3).name = "七米", this is the Go language syntactic sugar to help us achieve.

Structure initialization

The structure has not been initialized, its member variables are zero value corresponding to its type.

type person struct {
    name string
    city string
    age  int8
}

func main() {
    var p4 person
    fmt.Printf("p4=%#v\n", p4) //p4=main.person{name:"", city:"", age:0}
}

Use key-value pairs to initialize

When using the structure of the key-value is initialized, the key corresponding to the field structure, the initial value of the field should be.

p5 := person{
    name: "小王子",
    city: "北京",
    age:  18,
}
fmt.Printf("p5=%#v\n", p5) //p5=main.person{name:"小王子", city:"北京", age:18}

It may also be key to initialize pointers to structures, for example:

p6 := &person{
    name: "小王子",
    city: "北京",
    age:  18,
}
fmt.Printf("p6=%#v\n", p6) //p6=&main.person{name:"小王子", city:"北京", age:18}

When some fields with no initial value, the field can not write. In this case, the value field does not specify an initial value is the zero value of the field type.

p7 := &person{
    city: "北京",
}
fmt.Printf("p7=%#v\n", p7) //p7=&main.person{name:"", city:"北京", age:0}

Use the list of initialization values

Initialization structure can be abbreviated, which is initialized when the key is not to write, write directly to the value of:

p8 := &person{
    "沙河娜扎",
    "北京",
    28,
}
fmt.Printf("p8=%#v\n", p8) //p8=&main.person{name:"沙河娜扎", city:"北京", age:28}

With this initialization format, you need to pay attention to:

  1. All fields must be initialized structure.
  2. Filling sequence initial value must match the field order in the declaration of the structure.
  3. The method can not mix and key initialization method.

Structure of the memory layout

Structure occupies a contiguous memory.

type test struct {
    a int8
    b int8
    c int8
    d int8
}
n := test{
    1, 2, 3, 4,
}
fmt.Printf("n.a %p\n", &n.a)
fmt.Printf("n.b %p\n", &n.b)
fmt.Printf("n.c %p\n", &n.c)
fmt.Printf("n.d %p\n", &n.d)

Output:

n.a 0xc0000a0060
n.b 0xc0000a0061
n.c 0xc0000a0062
n.d 0xc0000a0063

[] Advanced knowledge about the Go language Recommended reading memory alignment: alignment in Go right memory

Interview questions

What Will the results of the following code?

type student struct {
    name string
    age  int
}

func main() {
    m := make(map[string]*student)
    stus := []student{
        {name: "小王子", age: 18},
        {name: "娜扎", age: 23},
        {name: "大王八", age: 9000},
    }

    for _, stu := range stus {
        m[stu.name] = &stu
    }
    for k, v := range m {
        fmt.Println(k, "=>", v.name)
    }
}

Constructor

Go structure of language has no constructor, we own realization. For example, the code below on the realization of a personconstructor. Because structare value types, if the structure is more complex, copies the value of the performance overhead will be relatively large, so that the constructor returns a pointer to a structure type.

func newPerson(name, city string, age int8) *person {
    return &person{
        name: name,
        city: city,
        age:  age,
    }
}

Call the constructor

p9 := newPerson("张三", "沙河", 90)
fmt.Printf("%#v\n", p9) //&main.person{name:"张三", city:"沙河", age:90}

Methods & Recipients

Go languages 方法(Method)is an action to a particular type of variable function. This particular type of variable called 接收者(Receiver). The concept is similar to the recipient in other languages thisor self.

The method is defined in the following format:

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
    函数体
}

among them,

  • Recipient variables: Parameter variable names when naming the recipient of the official recommended to use the name of the recipient of the first type lowercase letters, instead self, thisnamed the like. For example, Personthe type of a variable should be named recipient p, Connectorthe type of receiver should be named variable clike.
  • Type receiver: the receiver type and similar parameters, may be a pointer and non-pointer type type.
  • Method name, parameter list, return parameters: same as the specific format of the function definition.

for example:

//Person 结构体
type Person struct {
    name string
    age  int8
}

//NewPerson 构造函数
func NewPerson(name string, age int8) *Person {
    return &Person{
        name: name,
        age:  age,
    }
}

//Dream Person做梦的方法
func (p Person) Dream() {
    fmt.Printf("%s的梦想是学好Go语言!\n", p.name)
}

func main() {
    p1 := NewPerson("小王子", 25)
    p1.Dream()
}

The method and the difference function is not a function of any type, belonging to a specific type of method.

Pointer type recipient

Pointer type receiver a pointer to a structure of the composition, due to the characteristics of the pointer, pointer modify any recipient member variables when calling the method, after the method, the modifications are effective. In this way it is very close to other object-oriented languages is thisor self. For example, we Personadd a SetAgemethod to modify the age instance variable.

// SetAge 设置p的年龄
// 使用指针接收者
func (p *Person) SetAge(newAge int8) {
    p.age = newAge
}

This method is called:

func main() {
    p1 := NewPerson("小王子", 25)
    fmt.Println(p1.age) // 25
    p1.SetAge(30)
    fmt.Println(p1.age) // 30
}

Value type of recipient

When the method to value the role of recipient types, Go language code that will run when the value of the recipient's copy. In the method you can get the value of the type of the recipient of the recipient member values, but only for a copy of the modification operation, the recipient can not modify the variable itself.

// SetAge2 设置p的年龄
// 使用值接收者
func (p Person) SetAge2(newAge int8) {
    p.age = newAge
}

func main() {
    p1 := NewPerson("小王子", 25)
    p1.Dream()
    fmt.Println(p1.age) // 25
    p1.SetAge2(30) // (*p1).SetAge2(30)
    fmt.Println(p1.age) // 25
}

When should you use a pointer type receiver

  1. You need to modify the value of the recipient
  2. The recipient is a copy of the cost of a relatively large large object
  3. Ensure consistency, if there is a method using a pointer receiver, so other methods should use the pointer recipient.

Add any type of method

In the Go language, type the recipient may be of any type, not just the structure, can have any type of method. For example, we built based on intthe use of type keyword type can define new custom type, and then add a method to our custom type.

//MyInt 将int定义为自定义MyInt类型
type MyInt int

//SayHello 为MyInt添加一个SayHello的方法
func (m MyInt) SayHello() {
    fmt.Println("Hello, 我是一个int。")
}
func main() {
    var m1 MyInt
    m1.SayHello() //Hello, 我是一个int。
    m1 = 100
    fmt.Printf("%#v  %T\n", m1, m1) //100  main.MyInt
}

Note: non-native types can not be defined method, which means that we can not give other package type definition method.

Anonymous field structure

Structure does not allow its members to field the field name in the statement but only the type, not the name of this field is called an anonymous field.

//Person 结构体Person类型
type Person struct {
    string
    int
}

func main() {
    p1 := Person{
        "小王子",
        18,
    }
    fmt.Printf("%#v\n", p1)        //main.Person{string:"北京", int:18}
    fmt.Println(p1.string, p1.int) //北京 18
}

Anonymous fields default to the type name as the field name, the structure required field names must be unique, so a structure of the same anonymous type of field can only have one.

Nesting structure

A structural body may contain a nested structure or another structure pointer.

//Address 地址结构体
type Address struct {
    Province string
    City     string
}

//User 用户结构体
type User struct {
    Name    string
    Gender  string
    Address Address
}

func main() {
    user1 := User{
        Name:   "小王子",
        Gender: "男",
        Address: Address{
            Province: "山东",
            City:     "威海",
        },
    }
    fmt.Printf("user1=%#v\n", user1)//user1=main.User{Name:"小王子", Gender:"男", Address:main.Address{Province:"山东", City:"威海"}}
}

Anonymous nested structure

//Address 地址结构体
type Address struct {
    Province string
    City     string
}

//User 用户结构体
type User struct {
    Name    string
    Gender  string
    Address //匿名结构体
}

func main() {
    var user2 User
    user2.Name = "小王子"
    user2.Gender = "男"
    user2.Address.Province = "山东"    //通过匿名结构体.字段名访问
    user2.City = "威海"                //直接访问匿名结构体的字段名
    fmt.Printf("user2=%#v\n", user2) //user2=main.User{Name:"小王子", Gender:"男", Address:main.Address{Province:"山东", City:"威海"}}
}

We will first find the field in the structure when accessing structure members, can not find the look to go anonymous structure.

Field name conflict nested structure

Internal nested structure which may exist in the same field name. This time in order to avoid ambiguity need to specify the specific field of embedded structure.

//Address 地址结构体
type Address struct {
    Province   string
    City       string
    CreateTime string
}

//Email 邮箱结构体
type Email struct {
    Account    string
    CreateTime string
}

//User 用户结构体
type User struct {
    Name   string
    Gender string
    Address
    Email
}

func main() {
    var user3 User
    user3.Name = "沙河娜扎"
    user3.Gender = "男"
    // user3.CreateTime = "2019" //ambiguous selector user3.CreateTime
    user3.Address.CreateTime = "2000" //指定Address结构体中的CreateTime
    user3.Email.CreateTime = "2000"   //指定Email结构体中的CreateTime
}

Structure "inheritance"

Go language used in structures can also be implemented in other programming languages, object-oriented inheritance.

//Animal 动物
type Animal struct {
    name string
}

func (a *Animal) move() {
    fmt.Printf("%s会动!\n", a.name)
}

//Dog 狗
type Dog struct {
    Feet    int8
    *Animal //通过嵌套匿名结构体实现继承
}

func (d *Dog) wang() {
    fmt.Printf("%s会汪汪汪~\n", d.name)
}

func main() {
    d1 := &Dog{
        Feet: 4,
        Animal: &Animal{ //注意嵌套的是结构体指针
            name: "乐乐",
        },
    }
    d1.wang() //乐乐会汪汪汪~
    d1.move() //乐乐会动!
}

Visibility field structure

At the beginning of the field structure represented publicly accessible uppercase, lowercase represents private (defined only in the current packet structure can be accessed).

Sequence and structure of JSON

JSON (JavaScript Object Notation) is a lightweight data interchange format. Easy to read and write. It is easy for machines to parse and generate. JSON key-value pair is used to save a way JS object, key / value pair combination keys and double quotes EDITORIAL ""wrapped, colon :-separated, and then followed by value; English key between a plurality of ,separated .

//Student 学生
type Student struct {
    ID     int
    Gender string
    Name   string
}

//Class 班级
type Class struct {
    Title    string
    Students []*Student
}

func main() {
    c := &Class{
        Title:    "101",
        Students: make([]*Student, 0, 200),
    }
    for i := 0; i < 10; i++ {
        stu := &Student{
            Name:   fmt.Sprintf("stu%02d", i),
            Gender: "男",
            ID:     i,
        }
        c.Students = append(c.Students, stu)
    }
    //JSON序列化:结构体-->JSON格式的字符串
    data, err := json.Marshal(c)
    if err != nil {
        fmt.Println("json marshal failed")
        return
    }
    fmt.Printf("json:%s\n", data)
    //JSON反序列化:JSON格式的字符串-->结构体
    str := `{"Title":"101","Students":[{"ID":0,"Gender":"男","Name":"stu00"},{"ID":1,"Gender":"男","Name":"stu01"},{"ID":2,"Gender":"男","Name":"stu02"},{"ID":3,"Gender":"男","Name":"stu03"},{"ID":4,"Gender":"男","Name":"stu04"},{"ID":5,"Gender":"男","Name":"stu05"},{"ID":6,"Gender":"男","Name":"stu06"},{"ID":7,"Gender":"男","Name":"stu07"},{"ID":8,"Gender":"男","Name":"stu08"},{"ID":9,"Gender":"男","Name":"stu09"}]}`
    c1 := &Class{}
    err = json.Unmarshal([]byte(str), c1)
    if err != nil {
        fmt.Println("json unmarshal failed!")
        return
    }
    fmt.Printf("%#v\n", c1)
}

Structure tag (Tag)

TagMeta information structure can be read out by a mechanism at run-time reflection. TagAfter the structure defined above the field, by a pair of anti-wrap quotes, particularly the following format:

`key1:"value1" key2:"value2"`

Structure label of one or more key-value pairs. Keys and values separated by a colon, the value of double quotes. Use a space delimited between the pairs. Notes: written for the structure Tag, we must strictly abide by the rules of key-value pairs. Fault tolerance for resolving a code label structure is poor, once the wrong format, will not prompt any error during compilation and run-time, by reflecting the values can not be correct. For example, do not add a space between the key and value.

For example, we Studentuse the definition of each field in the structure json serialization Tag:

//Student 学生
type Student struct {
    ID     int    `json:"id"` //通过指定tag实现json序列化该字段时的key
    Gender string //json序列化是默认使用字段名作为key
    name   string //私有不能被json包访问
}

func main() {
    s1 := Student{
        ID:     1,
        Gender: "男",
        name:   "沙河娜扎",
    }
    data, err := json.Marshal(s1)
    if err != nil {
        fmt.Println("json marshal failed!")
        return
    }
    fmt.Printf("json str:%s\n", data) //json str:{"id":1,"Gender":"男"}
}

Exercises

  1. Use the "object-oriented" way of thinking to prepare a student information management systems.
    1. Students with id, name, age, scores and other information
    2. Program provides students show list, add students, student information edit, delete, students and other functions

Guess you like

Origin www.cnblogs.com/nickchen121/p/11517431.html