1. Use Pointers as receivers for methods

As long as the value is addressable, pointer methods can be called directly on the value. For a method, it is sufficient that its receiver is a pointer.

But not all values are addressable, such as elements of type map, variables referenced via interface:

type data struct { name string }

type printer interface { print() }

func (p *data) print() { fmt.Println(“name: “, p.name) }

Func main() {d1 := data{“one”} d1.print() // The d1 variable is addressable and can call the method of pointer receiver directly

Var in printer = data{"two"} in. Print () m := map[string]data{"x": Data {" three "}} m [r]. "x" print () / / m/" x "is not addressing / / changes frequentlyCopy the code

}

cannot use data literal (type data) as type printer in assignment: data does not implement printer (print method has pointer receiver) cannot call pointer method on m["x"] cannot take the  address of m["x"]Copy the code

2. Update the map field value

If a map field has a value of type struct, it cannot update a single field of that struct directly:

Type data struct {name string}

func main() { m := map[string]data{ “x”: {“Tom”}, } m[“x”].name = “Jerry” }

cannot assign to struct field m["x"].name in map
Copy the code

Because elements in a map are not addressable. To be distinguished, slice elements are addressable:

type data struct { name string }

func main() { s := []data{{“Tom”}} s[0].name = “Jerry” fmt.Println(s) // [{Jerry}] }

Note: Recently the GCCGO compiler was able to update the field values of map struct elements, but this was soon fixed. Officially, it is a potential feature of Go1.3, and does not need to be implemented in time. It is still in todo List.

There are two methods for updating the field values of struct elements in the map:

Using local variablesCopy the code

Type data struct {name string}

func main() { m := map[string]data{ “x”: {“Tom”}, } r := m[“x”] r.name = “Jerry” m[“x”] = r fmt.Println(m) // map[x:{Jerry}] }

Use map Pointers to elementsCopy the code

func main() { m := map[string]*data{ “x”: {“Tom”}, }

M [r]. "x" name = "Jerry" directly modified / / m/" x "in the field FMT Println (" x") (m) / / & {Jerry}Copy the code

}

But watch out for this misuse:

func main() { m := map[string]*data{ “x”: {“Tom”}, } m[“z”].name = “what???”

fmt.Println(m[“x”]) }

panic: runtime error: invalid memory address or nil pointer dereference
Copy the code

Nil interface and nil interface values

Although interface looks like a pointer type, it is not. A variable of type interface is nil only if both type and value are nil

If the value of your interface variable follows other variables (fog), be careful when comparing nil to equal:

func main() { var data *byte var in interface{}

fmt.Println(data, data == nil) // <nil> true fmt.Println(in, in == nil) // <nil> true in = data fmt.Println(in, In == nil) // <nil> false // Data is nil, but in is not nilCopy the code

}

If your function returns a value of type interface, beware of this trap: Func main() {doIt := func(arg int) interface{} {var result *struct{} = nil } else {return nil} return result}

if res := doIt(-1); res ! = nil { fmt.Println("Good result: ", res) } else { fmt.Println("Bad result: ", res) // Bad result: <nil> }Copy the code

}

4. Stack variables

You don’t always know whether your variables are assigned to the heap or stack.

In C++, variables created using new are always allocated to heap memory, but in Go, even if new() and make() are used to create variables, the allocation of memory for variables is still under the control of the Go compiler.

The Go compiler determines where to store a variable based on its size and the result of its “escape analysis”, so it returns the exact address of the local variable, which is not possible in C/C++.

When you add the -m parameter to go build or go run, you can accurately analyze the variable allocation position of the program:

Concurrency is a kind of Parallelism between Concurrency and Concurrency.

With Go 1.4 and below, only one execution context/OS thread is used, meaning that at most one Goroutine is executing at any one time.

The Go 1.5 version sets the number of executable contexts to Runtime.numcpu (), which is the number of logical CPU cores returned by the runtime.numcpu (). This can be adjusted using the GOMAXPROCS environment variable or dynamically using runtime.gomaxprocs ().

Misconception: GOMAXPROCS is the number of CPU cores that execute a Goroutine, see documentation

The value of GOMAXPROCS can exceed the actual number of cpus, up to 256 in 1.5

func main() { fmt.Println(runtime.GOMAXPROCS(-1)) // 4 fmt.Println(runtime.NumCPU()) // 4 runtime.GOMAXPROCS(20) Println(runtime.GOMAXPROCS(-1)) // 20 runtime.GOMAXPROCS(300) Println(runtime.GOMAXPROCS(-1)) // Go 1.9.2 // 300 }

5. Reorder read and write operations

Go may reorder the execution order of some operations, ensuring that operations are executed sequentially in a goroutine, but not in multiple Goroutines:

var _ = runtime.GOMAXPROCS(3)

var a, b int

func u1() { a = 1 b = 2 }

func u2() { a = 3 b = 4 }

func p() { println(a) println(b) }

Func main() {go u2() go p() time.sleep (1 * time.second)}

If you want to keep multiple goroutines executed sequentially as in the code, you can use locking mechanisms in the channel or sync package, etc. 6. Priority scheduling

Your program may have a goroutine that blocks other goroutines at runtime, such as a for loop that does not allow the scheduler to run:

func main() { done := false

go func() { done = true }() for ! done { } println("done !" )Copy the code

}

The body of the for loop need not be empty, but if the code does not trigger the scheduler execution, you will have a problem.

The scheduler executes after GC, Go declaration, blocking channel, blocking system call, and lock operations, as well as on non-inline function calls:

func main() { done := false

go func() { done = true }() for ! done { println("not done !" } println("done!" )Copy the code

}

The -m argument can be added to parse inline functions called in the for block:

You can also start the scheduler manually using Gosched() in the Runtime package:

func main() { done := false

go func() { done = true }() for ! done { runtime.Gosched() } println("done !" )Copy the code

}