This is the 10th day of my participation in the August More text Challenge. For details, see: August More Text Challenge

## 7.6 structure

### 7.6.1 Structure types

Sometimes we need to combine different types of data into an organic whole, for example: a student has attributes such as student number/name/gender/age/address. Obviously, it is complicated to define the above variables separately, and the data is not easy to manage.

A structure is an aggregated data type, which is a set of data consisting of a series of data of the same or different types. Each piece of data is called a member of the structure.

### 7.6.2 Struct initialization

#### 7.6.2.1 Common variables

``````type Student struct {
id   int
name string
sex  byte
age  int
}

func main(a) {
//1. Sequential initialization, each member must be initialized
var s1 Student = Student{1."mike".'m'.18."sz"}
s2 := Student{2."yoyo".'f'.20."sz"}
//s3 := Student{2, "tom", 'm', 20} //err, too few values in struct initializer

//2. Specifies that a member is initialized. If the member is not initialized, the value is zero
s4 := Student{id: 2, name: "lily"}}Copy the code``````

#### 7.6.2.2 Pointer variables

``````type Student struct {
id   int
name string
sex  byte
age  int
}

func main(a) {
var s5 *Student = &Student{3."xiaoming".'m'.16."bj"}
s6 := &Student{4."rocco".'m'.3."sh"}}Copy the code``````

### 7.6.3 Use of structure members

#### 7.6.3.1 Common variables

``````//=============== structure variables are common variables
//1, print the member
var s1 Student = Student{1."mike".'m'.18."sz"}
// Result: id = 1, name = mike, sex = m, age = 18, addr = sz
fmt.Printf("id = %d, name = %s, sex = %c, age = %d, addr = %s\n",

//2. Assign values to member variables
var s2 Student
s2.id = 2
s2.name = "yoyo"
s2.sex = 'f'
s2.age = 16
fmt.Println(s2) //{2 yoyo 102 16 guangzhou}
Copy the code``````

#### 7.6.3.2 Pointer variables

``````//=============== struct variables are pointer variables
//3, allocate space first, then assign value
s3 := new(Student)
s3.id = 3
s3.name = "xxx"
fmt.Println(s3) //&{3 xxx 0 0 }

//4, ordinary variable and pointer variable type print
var s4 Student = Student{4."yyy".'m'.18."sz"}
fmt.Printf("s4 = %v, &s4 = %v\n", s4, &s4)
//s4 = {4 yyy 109 18 sz}, &s4 = &{4 yyy 109 18 sz}

var p *Student = &s4
P. Member and (*p). Member operations are equivalent
p.id = 5
(*p).name = "zzz"
fmt.Println(p, *p, s4) //&{5 zzz 109 18 sz} {5 zzz 109 18 sz} {5 zzz 109 18 sz}
Copy the code``````

### 7.6.4 Structure comparison

If all members of a structure are comparable, then the structure is also comparable, in which case two structures can use == or! = operator, but > or < is not supported.

``func main() { s1 := Student{1, "mike", 'm', 18, "sz"} s2 := Student{1, "mike", 'm', 18, "sz"} fmt.Println("s1 == s2", s1 == s2) //s1 == s2 true fmt.Println("s1 ! = s2", s1 ! = s2) //s1 ! = s2 false }Copy the code``

### 7.6.5 Structure as function parameter

#### Pass 7.6.5.1 value

``````func printStudentValue(tmp Student) {
tmp.id = 250
//printStudentValue tmp = {250 mike 109 18 sz}
fmt.Println("printStudentValue tmp = ", tmp)
}

func main(a) {
var s Student = Student{1."mike".'m'.18."sz"}

printStudentValue(s)        // Pass the value. Changes to the parameter do not affect the argument
fmt.Println("main s = ", s) //main s = {1 mike 109 18 sz}
}
Copy the code``````

#### 7.6.5.2 Passing by reference

``````func printStudentPointer(p *Student) {
p.id = 250
//printStudentPointer p = &{250 mike 109 18 sz}
fmt.Println("printStudentPointer p = ", p)
}

func main(a) {
var s Student = Student{1."mike".'m'.18."sz"}

printStudentPointer(&s)     // Pass by reference (address). Changes to the parameter will affect the argument
fmt.Println("main s = ", s) //main s = {250 mike 109 18 sz}
}
Copy the code``````

### 7.6.2 visibility

The Go language is very stingy with keyword additions. There are no private, protected, or public keywords.

To make a symbol visible (that is, accessible) to other packages, you need to define the symbol to begin with an uppercase letter.

### 7.6.7 Structure Tag

Normally, you define a structure that looks like this, with each field consisting of a name and a field type

``````type Person struct {
Name string
Age  int
}
Copy the code``````

There are exceptions, such as the following, where an additional attribute can be added to the field, and the string contained in the backquote (the key below Esc) is called a Tag.

``````type Person struct {
Name string `json:"name"`
Age  int    `json:"age"`
}
Copy the code``````

So what does this label do?

Let’s take a look at the encoding/ JSON library and see what it does.

``package main import ( "encoding/json" "fmt" ) type Person struct { Name string `json:"name"` Age int `json:"age"` Addr string `json:"addr,omitempty"` } func main() { p1 := Person{ Name: "Jack", Age: 22, } data1, err := json.Marshal(p1) if err ! = nil {panic (err)} / / p1 Addr, will not print the FMT. Printf (" % s \ n ", data1) / / = = = = = = = = = = = = = = = = p2: Person of = {Name: "Jack", Age: 22, Addr: "China", } data2, err := json.Marshal(p2) if err ! Printf("%s\n", data2)} = nil {panic(err)}Copy the code``

Since the Addr field in the Person structure has the omitEmpty property, encoding/json converts an object to a JSON string if it finds that Addr in the object is false, 0, null pointer, empty interface, empty array, empty slice, empty map, One of the empty strings is ignored.

So when you run it, the output is as follows

``````\$ go run demo.go
{"name":"Jack","age":22}
Copy the code``````

#### How do I define a fetch Tag?

The Tag consists of one or more pairs of key and value pairs, separated by Spaces. Format is as follows

`key01:"value01" key02:"value02" key03:"value03"`

So once you’ve defined that, how do you get the Tag out of the structure?

The answer is what we learned in the last video, reflex.

Retrieving the Tag can be divided into three steps:

1. Get field
2. Get tag Tag
3. Get the key-value pair key:value

Demonstrate the following

``Field := reflect.typeof (obj).fieldByName ("Name") field := reflect.valueof (obj).type ().field (I) // I Field := reflect.valueof (&obj).elem ().type ().field (I) // Get Tag Tag := field.tag // Get key-value pair LabelValue := tag.get ("label") labelValue,ok := tag.lookup ("label") In fact, Get is just a simple encapsulation of the Lookup function. When the contents of the corresponding tag are not obtained, it returns an empty string. func (tag StructTag) Get(key string) string { v, _ := tag.Lookup(key) return v }Copy the code``

An empty Tag has the same effect as no Tag

``````package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string ` `
Age string
}
func main(a) {
p := reflect.TypeOf(Person{})
name, _ := p.FieldByName("Name")
fmt.Printf("%q\n", name.Tag) / / output ""
age, _ := p.FieldByName("Age")
fmt.Printf("%q\n", age.Tag) / / output ""
}
Copy the code``````

#### 3. Put it to the test: Do something with Tag?

Now that you know how to define tags and get them, you can practice doing a few things with them.

Let me give you an example here.

If I want to implement a function (let’s call it Print), I can beautify the output when I Print the Person object

``type Person struct { Name string Age int Gender string } person := Person{ Name: "MING", Age: 29,} Print(person) as follows, there is an is: between key and value, and if Gender is not specified, it is displayed as unknown. Name is: MING Age is: 29 Gender is: unknownCopy the code``

So how do you do that?

The Person structure is modified so that each field is tagged. All three fields have a label attribute, and Gender has a default attribute that specifies the default value.

``````type Person struct {
Name        string `label:"Name is: "`
Age         int    `label:"Age is: "`
Gender      string `label:"Gender is: " default:"unknown"`} and then write the Print functionfunc Print(obj interface{}) error {
/ / Value
v := reflect.ValueOf(obj)
// Parse the field
for i := 0; i < v.NumField(); i++ {
/ / remove the tag
field := v.Type().Field(i)
tag := field.Tag
// Parse label and default
label := tag.Get("label")
defaultValue := tag.Get("default")
value := fmt.Sprintf("%v", v.Field(i))
if value == "" {
// If no value is specified, the default value is used instead
value = defaultValue
}
fmt.Println(label + value)
}
return nil} Finally execute, look at the output, we expect: \$go run demo.go
Name is: MING
Age is: 29
Gender is: unknown
Copy the code``````

That concludes our introduction to the use of Tag.

# Common questions for beginners

## The difference between new and var a structure

``````package main

import "fmt"

type Vertex struct {
X, Y float64
}

func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}

func ScaleFunc(v *Vertex, f float64) {
v.X = v.X * f
v.Y = v.Y * f
}

func main(a) {
v := Vertex{3.4} // The value is returned
//ScaleFunc(v, 5)
ScaleFunc(&v, 10)
fmt.Println(v)

var v1 = new(Vertex)// The pointer is returned
ScaleFunc(v1, 10)
fmt.Println(v1)

var v Vertex
v.Scale(5)  // OK = (&v).scale (5).
p := &v
p.Scale(10) // OK

/* For the statement v.cale (5), methods with a pointer receiver can be called directly, even if v is a value and not a pointer. That is, since the Scale method has a pointer receiver, for convenience, Go will interpret the statement v.cale (5) as (&v).scale (5). * /
fmt.Println(v, p)
}
Copy the code``````

## The difference between methods and functions

``package main import ( "fmt" "math" ) type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func AbsFunc(v Vertex) float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func main() { v := Vertex{3, 4} fmt.Println(v.Abs()) fmt.Println(AbsFunc(v)) p := &Vertex{4, 3} FMT.Println(p.abs ()) FMT.Println(AbsFunc(*p))} /* A function that accepts a value as an argument must accept a value of the specified type: Var v Vertex FMT.Println(AbsFunc(v)) // OK FMT.Println(AbsFunc(&v)) // When a method with a value as the receiver is called, the receiver can be both the value and the pointer: Var v Vertex FMT.Println(v.abs ()) // OK p := &v FMT.Println(p.abs ()) // OK * /Copy the code``

Method can be automatically compatible.

The reception of the function is rigorously checked

## Select a value or pointer as the receiver

There are two reasons to use a pointer receiver:

First, a method can modify the value to which its receiver points.

Second, this avoids copying the value each time the method is called. This is more efficient if the type of the value is a large structure.

In this case, Scale and Abs receivers are of type *Vertex, even though Abs does not need to change its receivers.

In general, all methods of a given type should have a value or pointer receiver, but not a mix of the two.

``````package main

import (
"fmt"
"math"
)

type Vertex struct {
X, Y float64
}

func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}

func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
v := &Vertex{3, 4}
fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
v.Scale(5)
fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}
Copy the code``````