Struct is also an aggregated data type, and a struct can contain multiple values of any type, called fields of the struct.

1. Declare a structure

type Person struct {
    Name string
    Age int
    Birthday time.Time
}
Copy the code

The first letter of a structure field identifies the field’s permission access. Uppercase variables are accessible outside the package, and lowercase variables are private variables inside the package and used only inside the structure

2. The initialization

Ts := "2000-01-01 12:00:32" timeLayout := "2006-01-02 15:04:05" // Loc, _ := time.LoadLocation("Local") // Important: TheTime, _ := time.ParseInLocation(timeLayout, ts, Println(theTime) p := Person{Name:"zhanglinpeng",Age: 18, Birthday: // Finally, p2 := new(Persion) //new() creates a "zero value" structure, where all fields are initialized to zero values of the corresponding type. Zerostruct := struct{}{} // empty struct with length 0 bytesCopy the code

3. Anonymous structures

var apr = struct {
        Name string
        Age  int
    }{
        Name: "zhanglinpeng",
        Age: 13,
    }
    fmt.Println(apr)
Copy the code

4. Anonymous fields

var Student struct {
    string
    int
}
a := Student{"zhaoll", 19}
Copy the code

Note that the order of initialization cannot be changed, although it can be implemented syntactically, but in development, do not write this, it will be typed, one is bad readability, two is prone to error

5. Nested

type Person struct {
    Name string
    Age     int
    Contact  struct {
        Phone, Email, QQ string
    }
}
Copy the code

Initialization of an embedded anonymous structure can only be done by:

var apr = struct {
        Name string
        Age  int
        Contact struct {
            Phone, Email string
        }
    }{
        Name: "zhanglinpeng",
        Age: 13,
    }
    apr.Contact.Phone = "110"
    apr.Contact.Email = "[email protected]"
    fmt.Println(apr)
Copy the code

6. Value

When a structure is passed to a function as an argument, it is also passed as a value. If you want to modify the original structure, you can use a pointer


func changeName(pr *Person) {
    pr.name = "zhanglinpeng"
}
...
changeName(&person)
fmt.Println(person)
Copy the code

7. Obtain attribute values

You can use the point operator to get property values, which can also be applied to struct Pointers.

person := &person{Name:"weishihao",Age:14,... } person.Name = "zhaoyuhao"Copy the code

8. Structural comparison

var Person struct {
    Name string
    Age int
} 
p1 := Person{Name:"zhaojj", Age: 14}
p2 := Person{Name:"zhaojj", Age: 14}
p3 := Person{Name:"zhaojj", Age: 15}
fmt.Println(p1 == p2) // true
fmt.Println(p1 == p3) // false
Copy the code

Combination of 9.

type Person struct {
    Gender int
}

type teacher struct {
    Person
    Name string
    Age int
}

type student struct {
    Person
    Name string
    Age int
}

t1 := teacher{Name:"mayun", Age: 44, Person: Person{Gender: 0}}
s1 := student{Name: "zhaojj", Age: 12, Person: Person{Gender: 1}}
t1.Name = "yangmi"
s1.Gender = 0
Copy the code

We found that we could just click on s1.person. Gender = 0 instead, although it would have worked. So why is it possible to do this? All we have to do is embed a type as a field and enjoy what an embedded field has. He came, he came with all his possessions, and when he came to me, I could use all that he had, of course, without going through him. That’s it. If he implements any interface, he comes and I implement all the interfaces he implements. Look at that. Look at that.

If there is an attribute field with the same name in the embedded structure, you need to specify the access method, such as the one described above, when accessing the attribute field in the different structure. An error is reported if a property field of the same name exists in the peer embedded structure.

Why is there no inheritance? Object-oriented programming, in many well-known programming languages, involves much discussion of the relationships between types, which can often be derived automatically. Go takes a different approach.

In Go, a type automatically satisfies any interface that specifies a subset of its methods, rather than requiring programmers to declare in advance that two types are related. Types can satisfy multiple interfaces at the same time without the complexity of traditional multiple inheritance. Interfaces can be very lightweight — interfaces with one or even zero methods can express a useful concept. If new ideas come up, you can add interfaces after the fact, or you can test them without commenting on the original type. Because there is no explicit relationship between types and interfaces, there is no need to manage or discuss type hierarchies.

Method 10.

We just need to prefix the normal function with receiver (written in parentheses before the function name) so that the compiler knows which struct the function (method) belongs to. Note that since Go does not support function overloading, only one function corresponds to a method on a receiver. For example, the following is method duplication.

type A struct {
    Name string
}
type B struct {
    Name string
}

func (a A) print() {
    fmt.Println("function A")
}

func (b B) print() {
    fmt.Println("function B")
}

func (b B) print(i int) {
    fmt.Println("function B with argument")
}
Copy the code

For structure A and B, the print method is different, so it can coexist peacefully. But for structure B, there are two print methods with the same name, so an error will be reported.

Struct value method and pointer method

package main

import (
	"fmt"
)

type User struct {
	Id   int
	Name string
}

func (u User) displayId() {
	fmt.Println(u.Id)
}

func (u *User) displayName() {
	fmt.Println(u.Name)
}

func main() {
	us := User{Id: 1, Name: "zhao"}
	us.displayId() // 1
	us.displayName() // zhao
	us2 := &User{Id: 2, Name: "qian"}
	us2.displayId() // 2
	us2.displayName() // qian
}
Copy the code

As you can see, either a structure variable or a structure pointer variable is a method that can call the recipient of either a structure or a structure pointer.

In fact, the above mentioned is relatively general, specifically (the following two points are extracted from Go Language core 36 Lecture 13 of Teacher Hao) :

  • The receiver of a value method is a copy of the type of value that the method belongs to. The changes we make to the copy in this method are generally not reflected in the original value, unless the type itself is an alias type of a reference type (such as a slice or dictionary). The recipient of a pointer method is a copy of the pointer value of the primitive type to which the method belongs. If we modify the value that the copy points to in such a method, the original value will always be reflected.
  • A collection of methods of a custom data type contains only all of its value methods, whereas a collection of methods of a pointer type contains all of its value methods and all of its pointer methods. Strictly speaking, we can only call the value method on a value of such a primitive type. However, the Go language automatically translates for us in time, allowing us to call its pointer methods on such values. For example, on the Cat variable Cat, we can change the Cat’s name with cat.setName (“monster”) because Go automatically translates it to (& Cat).setname (“monster”) : The SetName method is called on the value of a pointer to cat.

However, there is a difference when passed to the interface, and this is the most important difference between a value method and a pointer method. Take a look at the following example:

package main import ( "fmt" ) type DisplayInfo interface { displayId() displayName() } type User struct { Id int Name string } func (u User) displayId() { fmt.Println(u.Id) } func (u *User) displayName() { fmt.Println(u.Name) } func DisplayUserInfo(ds DisplayInfo) { ds.displayId() ds.displayName() } func main() { us := User{Id: 1, Name: "zhao"} us.displayId() us.displayName() us2 := &User{Id: 2, Name: "Qian "} us2.displayId() us2.displayName() us3 :=User{Id:3,Name:"sun"} &user {Id:3,Name:"sun" DisplayUserInfo(us3) // cannot use us3 (type User) as type DisplayInfo in argument to DisplayUserInfo // User does not implement DisplayInfo (displayName method has pointer receiver) }Copy the code

The error message says that the User type does not implement the DisplayInfo interface because the displayName method receiver is a pointer. Us3 = &user {Id:3,Name:”sun”} This is because when the receiver is a pointer type, it means that the structure to which the pointer points implements the interface and when the receiver is a value type, it means that the structure itself implements the interface. Those whose recipients are T belong to one set of methods, and those whose recipients are *T are another set of methods, including those whose recipients are *T and T.

12. The type of the recipient determines whether the bound structure can be modified

package main

import "fmt"

type A struct {
    Name string
}
type B struct {
    Name string
}

func (a A) print() {
    a.Name = "FuncA"
    fmt.Println("function A")
}

func (b *B) print() {
    b.Name = "FuncB"
    fmt.Println("function B")
}
func main() {
    a := A{}
    a.print()
    fmt.Println(a.Name)  // ""
    b := B{}
    b.print()
    fmt.Println(b.Name) // "FuncB"
}
Copy the code

13. The method binding itself can only bind types within the package

If the type is outside the package, we cannot bind the method. That’s why a type alias doesn’t bring a method on a type into the current package, so if I define an int in the current package, then I have to implement a method on an int, right

14. method value VS method expression

There are actually two kinds of calls, the one described above is officially called Method Value, and the other is called Method expression

package main import "fmt" type A struct { Name string } func (a *A) print() { a.Name = "FuncA" fmt.Println("function A")  } func main() { a := A{} a.print() // method value (*A).print(&a) // method expression (&a).print() }Copy the code

15. Method permissions

Finally, access. Because Go is case sensitive to whether it is public or private, but is package-specific, everything in the package can be accessed, whereas method bindings themselves can only bind types in the package, so methods can access all members of the receiver.

16.demo

package main

import (
    "fmt"
    "unsafe"
)

type User struct {
    subject [10]byte
}

func main() {
    user := new(User)
    fmt.Println(user.subject) // [0 0 0 0 0 0 0 0 0 0]
    fmt.Println(len(user.subject)) // 10
    fmt.Println(reflect.TypeOf(user)) // *main.User
    fmt.Println(unsafe.Sizeof(struct{}{})) // 0
}
Copy the code

17. Existing misunderstandings

It is generally assumed that passing in a pointer type can change the value of a parameter in a function call. This is true, but it depends, for example

package main import ( "fmt" "unsafe" ) type User struct { Name string } func Change(u *User) { Ftt.println (unsafe.pointer (u)) // The value here is the same as in main ftt.println ("-----") u = &user {Name: Println(unsafe.pointer (u))} func main() {u := &user {Name: "zhao"} fmt.Println(unsafe.Pointer(u)) Change(u) fmt.Println(u.Name) }Copy the code

Do you think the above changes will update the Name of u in main? The answer is no, because parameter passing is a value copy, even an address is a copy of the address value. So in the main function, the u.name value remains unchanged

But if you change the value of the structure specified in the address value passed in, this can change the original structure field. Such as the following

package main

import (
        "fmt"
        "unsafe"
)

type User struct {
    Name string
}


func Change(u *User) {
    u.Name = "dsfjeo"
    fmt.Println(unsafe.Pointer(u))
}

func main() {
     u := &User{Name: "zhao"}
     fmt.Println(unsafe.Pointer(u))
     Change(u)
     fmt.Println(u.Name)
}
Copy the code

Thus, the output of the result is a modified U.name value that can be printed.