1. The structure

A struct is a collection of fields. Belongs to a value type.

type Vertex struct {
    X int
    Y int
}

func main(a) {
    v := Vertex{1.2}
    v.X = 4
    fmt.Println(v.X)
}
Copy the code

Type is the definition type. It’s not required.

var s struct{
    x string
    y int
}
func main(a) {
    s.x = "title"
    s.y = 10
}
Copy the code

The above is an anonymous structure that is commonly used to organize global variables or as a temporary data template.

// Define, initialize, and assign to data
data := struct {
    name string
    age int} {"Richard".18,}Copy the code

2. The function

In Golang, a function is a first-class citizen and a type

func foo(x int, y int) { // No return value
    fmt.Println(x + y)
}
func add(x, y int) int { // Has a return value and can be abbreviated
    return x + y
}
func split(sum int) (x, y int) { // Multiple return values
    x = sum * 4 / 9
    y = sum - x
    return  // Name the return value, which can no longer be displayed as write
}
// foo("Hello", 1, 2, 3, 4, 5)
func foo(title string, y ...int) { // Variable argument, y is the slice type
    fmt.Println(title, y)
}
Copy the code

Multivalued returns: Functions can return any number of return values named return values: The return value of Go can be named and used like a variable

The defer statement delays the execution of the function until the upper function returns. The arguments to the deferred call are generated immediately, but the function is not called until the upper function returns.

Delayed function calls are pushed onto a stack. When the function returns, the delayed function call is called in lifO order

The init function

The init() function is used to initialize the package before the program is executed, such as initializing variables in the package. A package can export multiple init() functions, and a source file can contain multiple init() functions. The order in which multiple init() functions are executed in the same package is not clearly defined, but the init functions in different packages are determined by the package import dependencies; The init() function cannot be explicitly called in code and cannot be referenced (assigned to function variables), otherwise a compilation error will occur; If A package is referenced multiple times, such as A import B,C import B,A import C, B is referenced multiple times, but package B is initialized only once. Introduce package, do not appear dead cycle bad. A import B,B import A, in which case the compilation fails;

The function is a morphable parameter

func hello(num … Hello ([]int{5, 6, 7}…) Or hello(4,5,6) can pass slice into a mutable function without creating a new slice. Changing num will change the underlying array of the slice passed in.

Pointer parameter

The use of Pointers as parameters is often used to modify values, such as for basic data exchange

func swap(a, b *int) {
	temp := *a  // Cache the value of a instead of the address
	*a = *b
	*b = temp
}
Copy the code

When the pointer parameter is passed in, it copies the address of the pointer. Modifying the address of the pointer in the function does not modify the original pointer, as shown in the following example:

func ChangeAddr(a *int) {
	fmt.Printf("Addr: %v Value: %d \n", a, *a)
	b := 20
	a = &b
	fmt.Printf("Addr: %v Value: %d \n", a, *a)
}
func main(a) {
	var a = 10
	var pa = &a
	fmt.Printf("Addr: %v Value: %d \n", pa, *pa)
	ChangeAddr(pa)
	fmt.Printf("Addr: %v Value: %d \n", pa, *pa)
}
Copy the code

The output is as follows, and you can see that the original variable pa has not been changed after the function ends.

Addr: 0xc0000140d8  Value: 10 
Addr: 0xc0000140d8  Value: 10 
Addr: 0xc0000140f8  Value: 20 
Addr: 0xc0000140d8  Value: 10 
Copy the code

methods

In addition to the common constructs that can define methods, other types can also be defined:

type N int
func (n N) test(a){
    fmt.Println(n)
}
func main(a)  {
    var n N = 10
    f := n.test
    f()
    
    f1 := N.test
    f1(n) // equivalent: n.test (n)

    f2 := (*N).test
    f2(&n) // equivalent :(*N).test(&n)
}
Copy the code

Title: method calls

type People struct {
	Name string
}
func (p *People) test(a) {
	println("haha")}func main(a) {
	var a *People
	a.test()  // OK 
    People{}.test() // Error: People{} is not addressable
}
Copy the code

3. interface

In Golang, the interface is the first citizen and belongs to the value type.

Implement the interface using duck typing: Anyone who looks like a duck thinks it’s a duck.

// As long as the implementation of the speak method, is the speaker type
type speaker interface {
    speak()
}
type cat struct{}
type dog struct{}

func (c cat) speak(a) {}
func (d dog) speak(a) {}

func say(x speaker) {
    x.speak()
}

// Cat dogs are speaker types
var c cat
var d dog
say(c)
say(d)
Copy the code

Empty interface interface {}

Empty interface: an interface that does not define any methods. So any type implements a null interface.

Map [string]interface{} This allows you to use any type of map value. The func show(a interface{}) {} parameter can pass in any type of value.

Interface {} can accept any type of argument, even for receiving pointer types use interface{} instead of *interface{}.

The pointer receiver of the method

There are two types of recipients of a method, a value receiver and a pointer receiver

type People interface {
    Speak(string) string
}

type Student struct{}

func (stu *Student) Speak(think string) (talk string){... }func main(a) {
    var peo People = Student{} * / *Student * / *Student * /
    fmt.Println(peo.Speak("speak"))}Copy the code

In addition, the value receiver, which is the type of the receiver, is a value, which is a copy, and the method itself cannot change its real receiver; The type of the pointer receiver is a pointer that is a reference to the receiver, which can be modified to affect the real receiver.

type Person interface {
    getName() string
    setName(string)}type Student struct {
    name string
}

func(p Student) getName(a) string {
    return p.name
}

func(p Student) setName(name string) { / / # 1
    p.name = name
}

func main(a) {
    var student Person = Student{name: "Unknown"} / / # 2
    fmt.Printf("Uninitialized default: s1:%s\n", student.getName())
    student.setName("Richard")
    fmt.Printf("S1 :%s\n", student.getName())
}

// You cannot change the name above
// To use it correctly, change #1 to pointer receiver:
// func(p *Student) setName(name string) { // #1
// Initialize to:
// var student Person = &Student{name: "Unknown"} // #2
Copy the code

Types of assertions

The type assertion x.(T) returns two values, the first being the value of the variable and the second a Boolean value

For example, v, ok := x.(string) OK indicates whether the value is a string, and v indicates a specific value. It can only be used on interfaces.

Type assertion I. (T) can only be used on interfaces. Where I is the interface and Type is the Type or interface. The dynamic Type of I is automatically checked for consistency with Type at compile time. However, if the dynamic type does not exist, the assertion always fails

func main(a) {
    x := interface{},nil)
    y := (*int) (nil)
    a := y == x
    b := y == nil
    _, c := x.(interface{})
    println(a, b, c)
    fmt.Printf("%T %T \n", x, y)
}
// false true false
// <nil> *int 
Copy the code