Install Go environment
Installation package download address: https://golang.org/dl/ , it can't be opened https://studygolang.com/dl Download.
After the download and installation is completed, you can open Win+R and enter cmd to check whether the installation is successful. If you enter go version successfully and display the version number, the installation is successful
Install integrated development environment
LiteIDE download address: http://liteide.org/cn/
You can use LiteIDE, the integrated development environment of Go, or IntelliJ Idea to install the Go plug-in.
Plug in installation path: File - > Settings
elements of grammar
package
Package declaration
The first line of each go file declares which package the file belongs to. The package name defines the package name of the file. The main package represents an independent and runnable Go program. Each go application contains a package called main.
package main
Import of packages
Use the import keyword + package name to import the dependent package. The package name uses double quotation marks.
import "fmt" import "math"
You can also import packages in parentheses
import ( "fmt" "math" )
Export name
In go, you can only use the exported functions in the module. The exported functions begin with uppercase letters. Methods that begin with lowercase letters can only be used within a package.
package main import ("fmt" "math" ) func main() { fmt.Printf("%g", math.Sqrt(2)) }
package main import ("fmt" "math" ) func main() { fmt.Printf("%g", math.sqrt(2)) }
function
Function definition
The functions in go are defined with the func keyword. Note that the parameter type is after the parameter name, and the format is as follows
func Function name(Parameter name 1 parameter type, Parameter name 2 parameter type) Return value { }
package main import ( "fmt" ) func main() { fmt.Printf("3 + 5 = %d", add(3, 5)) } func add(a int, b int) int { return a + b }
Parameter list simplification
When two or more parameter types are the same, only the last parameter type can be reserved. As above, the function add can be simplified to
func add(a, b int) int { return a + b }
Multiple return values
Functions in go can return any number of return values
package main import ( "fmt" ) func main() { a, b := add(3, 5) fmt.Printf("3 + 5 = %d, 3 - 5 = %d", a, b) } func add(a, b int) (int, int) { return a + b, a - b }
Name of return value
The return value can be named directly. The return statement without parameters returns the named return value
func add(a, b int) (sum, difference int) { sum = a + b difference = a - b return }
variable
Variables are defined with the var keyword, and the scope can be packages or functions.
var flag bool func main() { var i int flag = true i = 5 fmt.Println(i, flag) }
Initialization of variables
A variable can be initialized at the time of declaration. If the value of the variable is initialized at the time of declaration, the type can be omitted, and the variable can obtain the type from the value.
var flag = true func main() { var i = 5 fmt.Println(i, flag) }
Short assignment statement
In the function: = can replace the var declaration in the variable assignment with explicit type, but it cannot be used outside the function
func main() { i := 5 fmt.Println(i, flag) }
Basic data type
The basic data types in go can also be divided into three categories: integer, floating point and Boolean
integer
The data types of integers include int8, int16, int32, int64, uint8, uint16, uint32, and uint64. The integers beginning with int are signed integers, and the bits beginning with unit are unsigned integers
float
The data types of floating-point type include float32, float64, complex64, complex128, uint8, uint16, uint32 and uint64, where the integer starting with int is signed and the bit unsigned integer starting with unit is unsigned.
float is used to represent floating-point data, and complex table is a complex type
Boolean type
Boolean values can only be constants true or false
Other numeric types
Other numeric types include byte and run.
byte is equivalent to int8 and is often used to process ascii characters
rune is equivalent to int32 and is commonly used to handle unicode or utf-8 characters
// rune is an alias for int32 and is equivalent to int32 in all ways. It is // used, by convention, to distinguish character values from integer values. //The alias of int32 is equivalent to int32 in almost all aspects //It is used to distinguish between character values and integer values type rune = int32
Zero value
Variables that are not assigned a value are set to zero
Digital: 0
Boolean: false
String: ''
package main import ( "fmt" ) var ( flag bool MaxInt uint64 str string ) func main() { fmt.Printf("Type: %T Value: %v\n", flag, flag) fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt) fmt.Printf("Type: %T Value: %v\n", str, str) }
Branching structure
There is only one loop structure in go language: for
for
Compared with other languages, the parentheses of for in go can be omitted
sum := 0 for i:= 1; i < 100; i ++ { sum += i } fmt.Printf("sum = %v", sum)
In addition to conditional expressions, initialization statements and post statements are optional
sum := 1 for sum < 10 { sum += sum } fmt.Printf("sum = %v", sum)
An infinite loop statement can be regarded as a for statement without a conditional expression
for { }
if
The if statement is similar to the for statement. Parentheses can be omitted, but braces cannot
flag := true if flag { fmt.Printf("true") } else { fmt.Printf("false") }
If can make some initialization statements before determining the conditional expression, and the scope of the statement is only valid in the if statement
import ( "fmt" "math" ) func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v } return lim } func main() { fmt.Println( pow(3, 2, 10), pow(3, 3, 20), ) }
switch
The case statements of switch in go are executed sequentially from top to bottom until the matching is successful. Case penetration will not occur, and only the first case that meets the conditions will be executed instead of the following cases
import ( "fmt" "runtime" ) func main() { fmt.Print("Go runs on ") switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X.") case "linux": fmt.Println("Linux.") case "windows": fmt.Println("windows") default: fmt.Printf("NULL") } }
defer
The statement decorated with defer will be pushed to the call stack and executed after the outer function returns. If multiple statements are decorated with defer, follow the order of last in first out
fmt.Println("counting") for i := 0; i < 10; i++ { defer fmt.Println(i) } fmt.Println("done")
Pointer
There are pointers in go, but pointer calculation is not allowed. The * type declares this type of pointer, and the zero value is < nil >.
Use the & operator to generate a pointer to the specified operand.
func main() { i := 1 var p *int fmt.Println(p) p = &i//Defines the pointer p to the variable i fmt.Println(p)//Storage address of variable i in memory fmt.Println(*p) *p = *p + 1 fmt.Println(*p) }
structural morphology
A struct is a set of fields that can be used Number to access the fields in the structure
type Coordinate struct { X int Y int } func main() { v := Coordinate{1, 2} fmt.Println(v.X) }
You can use structure pointers to access data, or you can implicitly refer to it indirectly
type Coordinate struct { X int Y int } func main() { var p *Coordinate p = &Coordinate{1, 2} fmt.Println((*p).X)//Access through structure pointer fmt.Println(p.X)//Implicit indirect access }
You can use the method of listing field values to allocate the structure. The field without assigned value is the zero value of this type
type Coordinate struct { X int Y int } func main() { var p *Coordinate p = &Coordinate{X:1} fmt.Println((*p).X) fmt.Println(p.Y) }
array
go uses [] type to declare array
func main() { a := [5]int{1,2,3,4,5} fmt.Println(a) }
section
The size of the array is fixed. Slicing provides dynamic size and flexible perspective for array elements.
Slices are defined by two subscripts, an upper bound and a lower bound, separated by colons:
Include lower bound but not upper bound
func main() { a := [5]int{1,2,3,4,5} var p = a[0:4] fmt.Println(p) }
a[0:4] indicates the elements with subscripts 0 to 3 in the a array. The slice does not really store data, but only describes a piece of data in the array. Modifying the slice will modify the corresponding elements in the array.
func main() { a := [5]int{1,2,3,4,5} var p = a[0:3] var q = a[1:4] fmt.Println(p) fmt.Println(q) p[2] = 9 fmt.Println(p) fmt.Println(q) }
Slice can omit the upper and lower bounds. The default value of the lower bound is 0, and the default value of the upper bound is the length of the array
For array a [10]int, the following slice is equivalent
a[0:10] a[:10] a[0:] a[:]
The length of the slice refers to the number of elements stored, and the capacity refers to the number of elements from the first element of the slice to the last element of the underlying array.
func main() { s := []int{1, 3, 5, 7, 9, 11} printSlice(s) // Cut the slice so that its length is 0 s = s[:0] printSlice(s) // Extended length s = s[:4] printSlice(s) // Discard the first two values s = s[2:] printSlice(s) // Extended length s = s[:4] printSlice(s) } func printSlice(s []int) { fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) }
The slice has a zero value of nil and no underlying array
func main() { var s []int fmt.Println(s, len(s), cap(s)) if s == nil { fmt.Println("nil!") } }
Slices can be created with the built-in function make. In case of two parameters, the second parameter is length and capacity. In case of three parameters, the second parameter is length and the third parameter is capacity
func main() { a := make([]int, 5) fmt.Println(len(a), cap(a)) s := make([]int, 0, 5) fmt.Println(len(s), cap(s)) }
You can append elements to the slice through append. If the capacity of the underlying array is insufficient, a new array will be created and the slice will point to the new array.
func main() { var language = []string{"Java", "C", "Python"} fmt.Printf("first element address:%v, len:%d, cap:%d, %v\n", &language[0], len(language), cap(language), language) language = append(language, "Golang", "Scala", "Lua") fmt.Printf("first element address:%v, len:%d, cap:%d, %v\n", &language[0], len(language), cap(language), language) }
The range form of the for loop can traverse slices or maps. When the for loop is used to iterate through slices, two values are returned for each iteration. The first value is the subscript of the current element, and the second value is a copy of the element corresponding to the subscript.
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} func main() { for i, v := range pow { fmt.Printf("2**%d = %d\n", i, v) } }
range can also assign subscripts or values to_ To ignore it. When only index is needed, the second variable can be ignored
func main() { pow := make([]int, 10) for i := range pow { pow[i] = 1 << uint(i) // == 2**i } for _, value := range pow { fmt.Printf("%d\n", value) } }
mapping
Map maps keys to values. The zero value of the map is nil. Nil mapping has no keys and cannot add keys.
The make function returns a map of the given type and initializes it for standby.
type Person struct { Weight, Height float64 } var m map[string]Person func main() { m = make(map[string]Person) m["Bill"] = Person{ 70, 180, } fmt.Println(m["Bill"]) }
If the mapped element types are the same, you can declare the type only in the outer layer
type Person struct { Weight, Height float64 } var m map[string]Person func main() { m = map[string]Person{ "Bill":{70, 180}, "John":{85, 195}, } fmt.Println(m) }
You can get, modify and delete mapping elements, or use double assignment to detect whether a key exists
type Person struct { Weight, Height float64 } var m map[string]Person func main() { m = map[string]Person{ "Bill":{70, 180}, "John":{85, 195}, "Mary":{55, 168}, } fmt.Println(m) fmt.Println(m["John"]) m["Bill"] = Person{75, 180} fmt.Println(m) delete(m, "John") fmt.Println(m) param1, ok := m["Jack"] fmt.Println(param1, ok) param2, ok := m["Bill"] fmt.Println(param2, ok) }
go process
Go provides a lightweight thread goroutine to execute functions, using the go function name.
import ( "fmt" "time" ) func say(s string) { for i := 0; i < 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) } } func main() { go say("world") say("hello") }
channel
A channel is a pipe with a type. Create a channel through the make and chan keywords, and send or receive values through the channel operator < -.
The channel can be buffered. Provide the buffer length as the second parameter to make to initialize a buffered channel,
Blocking occurs only when the channel's buffer is full and data is sent to it. When the buffer is empty, the receiver blocks.
import "fmt" func sum(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum } func main() { s := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], c) x, y := <-c, <-c fmt.Println(x, y, x+y) }
If the above code is changed to
func main() { s := []int{7, 2, 8, -9, 4, 0} c := make(chan int, 1) sum(s[:len(s)/2], c) sum(s[len(s)/2:], c) x, y := <-c, <-c fmt.Println(x, y, x+y) }
When the buffer is added and the go process is removed, a lock conflict occurs
Select
The select statement enables a Go procedure to wait for multiple communication operations. Select will block until a branch can continue to execute, and then the branch will be executed. When multiple branches are ready, a random one is selected for execution.
When none of the other branches in the select are ready, the default branch is executed. To avoid blocking when trying to send or receive, use the default branch:
import ( "fmt" "time" ) func main() { tick := time.Tick(100 * time.Millisecond) boom := time.After(500 * time.Millisecond) for { select { case <-tick: fmt.Println("tick.") case <-boom: fmt.Println("BOOM!") return default: fmt.Println(" .") time.Sleep(50 * time.Millisecond) } } }
Mutex
Sync is available in the Go standard library Mutex mutex type and its two methods: Lock Unlock
The Lock method can be invoked before the code to invoke the Unlock method after the code to ensure the mutex execution of a piece of code.
type SafeCounter struct { v map[string]int mux sync.Mutex } // Inc increases the value of the counter for a given key. func (c *SafeCounter) Inc(key string) { c.mux.Lock() c.v[key]++ c.mux.Unlock() } // Value returns the current value of the counter for a given key. func (c *SafeCounter) Value(key string) int { c.mux.Lock() defer c.mux.Unlock() return c.v[key] } func main() { c := SafeCounter{v: make(map[string]int)} for i := 0; i < 100; i++ { go c.Inc("key") } fmt.Println(c.Value("key")) }