1. Overview
Go is an open-source programming language that makes it easy to build software that is simple, reliable, and efficient. Go was developed from the end of 2007 by Robert Griesemer, Rob Pike, Ken Thompson, and later joined Ian Lance Taylor, Russ Cox, and eventually open source in November 2009, A stable version of Go 1 was released earlier in 2012. Now the go development is completely open and has an active community.
2. Pros and cons
2.1 Advantages
- Open source
- compiler language, running high-speed
- Simple syntax
- Parallel Processing Encapsulation
- Memory management, array security
2.2 Disadvantages
- Debugging as a compiled language is less convenient than scripting
- No script is available for data analysis
- No basic language flexibility for the underlying control
3. Use
It is often used in system programming languages that carry a WEB server, a giant central server that stores clusters or similar uses. In the field of high-performance distributed systems, the Go language is undoubtedly more efficient than most other languages. It provides a large amount of parallel support, the development advantage in the service side.
4. Language Basics
4.1 Basic data types
4.1.1 Variables and constants
Normal Assignment:
// var 变量名称 变量类型 = 值var num int = 1
Assign values in parallel
var num1,num2 int = 1, 2
Multi-line Assignment
var ( num1 int = 1 num2 int = 2)
4.1.2 The name and width of an integer type
There are 10 of the integer types of go. There are two integer types that are related to the calculation schema:
- Signed integer type int
- unsigned integer type UINT
On computers with different computing architectures, the widths they embody (the space required to store values of a type) are not the same. The unit of space can be a bit or byte.
Image
In addition to these two computed-schema-related integer types, there are 8 integer types that can explicitly express their own widths:
Image
4.1.2 notation for integer type values
Image
If you assign a value to the variable num with 8 binary:
num = 039 // 用"0"作为前缀以表明这是8进制表示法
If you assign a value to the variable num with 16 binary:
num = 0x39
4.1.3 Floating-point number types
There are two floating-point number types: The value of the Float32/float64 floating-point type is usually the integer part, the decimal point "." and fractional components. Another way to represent this is to add an exponential portion to it. The exponential portion is represented by the "E" or "E" and the signed 10-in integer. Example: 3.9E-2 represents floating point number 0.039. 3.9E+1 indicates floating point number 39.
Sometimes floating-point type values can also be simplified. For example, 39.0 can be reduced to 39. 0.039 can be simplified to. 039. The relevant part of the floating point in go can only be represented by the 10 binary notation.
4.1.4 plural type
There are two types of complex numbers: complex64 and complex128. In fact, the value of the complex64 type represents the real and imaginary parts of the complex number, respectively, by the values of the two float32 types. The value of the complex128 type is represented by a value of two float64 types representing the real and imaginary parts of the complex number.
The value of a negative type is generally composed of the real part of the floating-point number, the plus sign "+", the imaginary part of the floating-point representation, and the lowercase letter "I", such as 3.9E+1 + 9.99e-2i.
4.1.5 Byte and Rune
Both byte and Rune belong to the alias type. Byte is the alias type of uint8, and Rune is the alias type of Int32.
A rune type value can represent a Unicode character. A Unicode code point is typically represented by "u+" and an integer represented in hexadecimal notation, such as the Unicode code point for the English letter ' A ' as "u+0041".
The value of the Rune type needs to be wrapped by a single quote "'", but we can also express it in several other ways:
Image
In addition, several special sequences of characters are supported in the representation of the Rune type value, namely: Escape character. Such as:
Image
4.1.6 String Type
There are two representations of the string, namely, the native representation and the explanatory notation. In native notation, the character sequence needs to be wrapped with an inverted quotation mark "'", and if interpreted notation is used, the sequence of characters is enclosed in double quotation marks "" ".
var str1 string = “str”var str1 string = `str`
The difference between the two is that the former represents the WYSIWYG (except the carriage return). The latter represents a value in which the literal character will work.
The string value is immutable, and if we create a value of this type, it is impossible to make any modifications to it itself.
4.1.7 Array type
An array is a container that can hold several elements of the same type. The length of the array is fixed. Declare an array type as follows:
type MyNumbers [3]int
A type declaration statement consists of a keyword type, a type name, and a type literal
Above this type declaration statement is actually an array type [3]int declares an alias type.] This allows us to use mynumbers as an array type [3]int.
We represent the value of such an array type when. The type literal should be written to the leftmost, and then wrapped in curly braces to enclose several elements of that value, separated by commas (half-width), namely:
[3]int{1,2,3}
Now let's assign this array literal to a variable named numbers:
var numbers = [3]int{1,2,3}
This is a variable declaration statement that assigns a value to a variable while declaring it
Another way is to omit an array representing its length in the type literal, for example:
var numbers = [...]int{1,2,3}
You can access any one of the elements in the variable in the following way. Cases:
numbers[0]numbers[1]numbers[2]
If you want to modify one of the element values in an array value, you can:
numbers[1] = 4
You can get the array length in the following ways:
var length = len(numbers)
If an array is not assigned a value, its default value is
[length]type{0,0,0…}
4.1.8 Slice Type
Slices (slice) are also containers that can have several elements of the same type as arrays. Unlike arrays, the length of the slice type is indeterminate. Each slice value will use the array as its underlying data structure. The literal representation of the slice type is as follows:
[]int
Or is:
[]string
The declaration of a slice type can be this:
type MySlice []int
The representation of the slice value is also similar to the array value
[]int{1,2,3}
The method of manipulating array values also applies to slice values. There is also a way to manipulate an array called "slices," and the way to implement a slice is to slice the expression. Cases:
var number3 = [5]int{1,2,3,4,5}var slice1 = numbers3[1:4]
The result of the slice expression Numbers3[1:4] in the example above is that []int{2,3,4} is clearly tangent to the element that does not contain the upper-bound index of the element. Actually slice1 the underlying array of this slice value is the value of Number3.
We can also perform slice operations on slice values:
var slice2 = slice1[1:3]
In addition to the length slice value and the array value there is another property--capacity. The capacity of an array is always equal to its length, and the size of the slice value is often different from its length. Such as:
Image
, the capacity of a slice value is the absolute value of the index value of its first element value in its underlying array and the difference between the length of the array. You can use the CAP () built-in function to get the capacity of the array, slice, and channel type values:
var capacity2 int = cap(slice2)
The slice type belongs to the reference type, and its 0 value is nil, which is the null value. If we only declare a slice type without assigning it a value, its default value is nil.
More ways to manipulate slices sometimes we can put a third positive integer in square brackets. As shown in the following:
numbers3[1:4:4]
The third positive integer is the upper-bound index of the capacity, which means that the capacity of the slice value as a result can be set to a smaller size. It can restrict access to more elements in its underlying array through this slice value. The assignment statements for NUMBERS3 and slice in the previous section are as follows:
var numbers3 = [5]int{1,2,3,4,5}var slice1 = numbers3[1:4]
At this point, the value of the variable Slice1 is []int{2,3,4}. However, we can extend the length of the same as its capacity by doing the following:
slice1 = slice1[:cap(slice1)]
With this action, the value of the variable slice1 changes to []int{2,3,4,5}, and its length and capacity are all 4. The elements in the (1,5) range of the index values in the NUMBER3 value are now reflected in the value of Slice1. This is premised on the underlying array where the value of Number3 is the value of Slice1. This means that we can easily access more elements in their underlying array that are larger than the corresponding index values. If we write a function that returns such a slice value, then the program that gets it is likely to have access to elements that should not be exposed to it.
If we add a third index (that is, the upper-capacity index) to the slice, such as:
var slice1 = numbers3[1:4:4]
After that, we will not be able to access the Fifth element in the value of Number3 through Slice1.
Although the slice values are limited by their capacity in these respects. But we can extend it in an unrestricted way by another means. This requires the use of the built-in function append. Append expands the slice value and returns a new slice value, using the following method:
slice1 = append(slice1, 6, 7)
By doing this, the value of Slice1 becomes []int{2,3,4,6,7}. Once the expansion operation exceeds the capacity of the slice value being manipulated, the underlying array of the slice is replaced with the last action slice as "copy". The operation is implemented by invoking the copy function. The function receives two of the same slice values as parameters and copies the elements in the second parameter value to the corresponding position in the first parameter value (the index value is the same). Here are two points to note:
- This replication follows the principle of minimal replication, that is, the number of elements being copied is always equal to the length of the shorter parameter.
- Unlike the Append function, the copy function directly modifies its first parameter value.
Cases:
var slice4 = []int{0,0,0,0,0,0}copy(slice4, slice1)
With the above copy operation, Slice4 will become []int{2,3,4,6,7,0,0}.
4.1.9 Dictionary Types
The dictionary (MAP) type of the go language is the implementation of a hash table. The literal number of the dictionary type is as follows:
map[K]T
where "K" is the type of the key, and "T" represents the type of the element (value). If we describe a dictionary type with a key type of int and a value type of string:
map[int]string
The key type of the dictionary must be comparable, otherwise it will cause an error, i.e. the key cannot be a slice, dictionary, function type
The literal representation of a dictionary value is actually similar to the literal representation of an array's slices. The leftmost is still the type literal, and the right side is enclosed by curly braces and has a comma-separated key-value pair. The keys and values for each key-value pair are separated by colons. Take the dictionary type map[int]string as an example. The literal amount of his value can be this:
map[int]string{1:"a",2:"b"m,3:"c"}
We can assign this value to a variable
mm := map[int]string{1:"a",2:"b",3:"c"}
Use an index expression to remove a value from the dictionary:
b := mm[2]
You can assign a value with an index expression:
mm[2] = b + "2"
The value of the MM medium key of 2 becomes "B2". You can add a key-value pair to the dictionary in the following ways:
mm[4] = ""
For dictionary values, if the specified key does not have a corresponding value, the default is a null value of that type. So Mm[5] will return a "". But in that case we don't know if mm[5] is "or mm[5" without this value. So go provides another way to do this:
e, ok := mm[5]
The index expression for a dictionary can have two job search results, and the second job search result is of type bool. It is used to indicate whether a specified key-value pair exists in the dictionary value. The way to remove a key-value pair from a dictionary is simply to call the built-in function Delete:
delete(mm, 4)
Delete is deleted regardless of whether there is a key-value pair with a key of 4 in MM. The dictionary type belongs to the reference type, and its 0 value is nil
4.1.10 Channel Type
Channel is a very unique data structure in the go language. It can be used to pass typed data between different goroutine. and is concurrency-safe. In contrast, several previous data types are not concurrency-safe.
Goroutine can be seen as a vector that hosts code blocks that can be executed concurrently. They are dispatched by the run-time system of the go language and are executed concurrently by the operating system thread (also known as the kernel thread) to execute the code block.
The method of representing the channel type is simple and consists of only two parts:
chan T
In this type literal, the left side is the keyword Chan representing the channel type, and the right side is a mutable part that represents the type of data that the channel type allows to pass (or the element type of the channel).
Unlike other data types, we cannot represent a value for a channel type, so we cannot assign a value to a variable of a channel type by literal means. The purpose can only be achieved by invoking the built-in function make. The make parameter accepts two parameters, the first parameter is the literal of the type that represents the value to be initialized (example: Chan int), and the second parameter is the length of the value, for example, if we want to initialize a channel value with a length of 5 and an element type of int, you need to write:
make(chan int, 5)
The Make function can also be used to initialize the value of a slice type or dictionary type.
The data in the channel value is pre-FIFO. Below, we declare a variable of a channel type and assign it a value:
ch1 := make(chan string, 5)
In this way, we can use the Accept operator <-to send data to the channel value. Of course, it can also be used to receive data from the channel value, for example, if we want to send the string "value1" to the channel CH1, then we should do this:
ch1 <- “value1"
If we receive the string from CH1, this is the case:
<- ch1
We can assign the accepted string to a variable, such as:
value := <- ch1
As with index expressions for dictionary values, an accept operation on a channel value can have a second result value:
value, ok := <- ch1
The OK value here is of type bool. It represents the state of the channel value, true means that the channel value is valid, and False indicates that the channel value is invalid (or closed), and the deeper reason is that if the channel value is closed before or during the accept operation, the receive operation ends immediately and returns a 0 value of the element type of the channel value.
You can close a channel by using the function close:
close(ch1)
A duplicate shutdown of the channel value throws a run-time exception that causes the program to crash. If the channel value is valid, the send operation against it is blocked when the channel value is full (where the number of cached data is equal to its length). Sending data to a channel value that has been closed throws a run-time exception. A receive operation on a valid channel value is blocked when it is already empty. The channel type is a reference type and its 0 value is nil.
4.2 Process Control
4.2.1 Conditional statements
The corresponding keywords are if, else and else if;
if a := 1; a >= 1 { fmt.Println("OK")}
4.2.2 SELECT statement
The corresponding keywords are switch, case, and select
switch i { case 0: fmt.Printf("0") case 1: fmt.Printf("1") case 2: fallthrough case 3: fmt.Printf("3") case 4, 5, 6: fmt.Printf("4, 5, 6") default: fmt.Printf("Default")}
4.2.3 Loop Statements
The corresponding keywords are for and range;
sum := 0for i := 0; i < 10; i++ { sum += i}
4.2.4 Jump Statement
func myfunc() { i := 0 HERE: fmt.Println(i) i++ if i < 10 { goto HERE }}
4.3 functions
4.3.1 overview
First, the format of the function is fixed, func+ function name + parameter + return value (optional) + function body. Cases:
func main() {fmt.Println("Hello go")}
There are two special functions in Golang, the main function and the INIT function, the main function does not have to be described in all languages, it acts as an entry for a program and can only have one. The init function is optional in each package, dispensable, and can even have multiple (but strongly recommend an init function in the packages), and the Init function automatically calls the INIT function when you import it, so the init function does not need to be called manually by us. In addition, it will only be called once, because when a package is referenced more than once, it will only be imported once.
4.3.2 Parameter passing
Common variables
When using a normal variable as a function parameter, when passing a parameter it is only worth copying to the variable, and the value of the argument is copied to the variable parameter, and when the function handles the argument, it does not affect the value of the original argument.
Pointer
function variables can not only use ordinary variables, you can also use pointer variables, using pointer variables as parameters of the function, when the parameter is passed will be an address to see Bai, the actual parameter of the memory address is copied to the variable parameter, then the change of the parameter will affect the value of the argument.
Array
Unlike other languages, the go language is a copy of an array when it is used as a function parameter. Modification of an array element in a formal parameter does not affect the original value of the element.
Slice, map, chan
When using slice, map, chan as a function parameter, the parameter pass will be a copy of the address, the memory address of the underlying array is copied to the parameter slice, map, Chan. At this point, the operation of the slice, map, and Chan elements is the manipulation of the underlying array elements.
Function name
In the Go language, functions also act as a data type, so functions can also be used as arguments to functions.
4.3.3 return value
The go language can return a pointer to a local variable, because the Go language recycling mechanism is automatically present on the heap when it discovers a temporary variable on the referenced stack.
4.3.4 Closure Package
Similar to other languages, Golang also supports closure functions
package mainimport "fmt"func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum }}func main() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), neg(-2*i), ) }}
Class 4.4
4.4.1 Overview
type Poem struct { Title string Author string intro string}
This declares a class in which there is no public, protected, private declaration. Golang uses a different approach to access the property: The first letter of the property is capitalized and can be accessed in other packages, otherwise it is only accessible in this package. This is also true of the Declaration and method of the class .
4.4.2 method
func (poem *Poem) publish() { fmt.Println("poem publish")}
Or
func (poem Poem) publish() { fmt.Println("poem publish")}
Unlike other languages, Golang declares that the method is consistent with the normal method, but adds a declaration such as poem poem after Func. the difference between adding and not adding * is that one is passing a pointer object and one is passing a value object.
Note When Method 1 is created, Method 2 is created by default, and vice versa.
Instantiation of the 4.4.3 class
There are several ways of instantiating an object
poem := &Poem{}poem.Author = "Heine"poem2 := &Poem{Author: "Heine"}poem3 := new(Poem)poem3.Author = "Heine"poem4 := Poem{}poem4.Author = "Heine"poem5 := Poem{Author: "Heine"}
The property value can be initialized when instantiated, and defaults to the system default if not indicated.
4.4.5 Pseudo-Inheritance
There is no inheritance in Golang, but a similar effect can be achieved using a combination of methods.
func (e *Poem) ShowTitle() { fmt.Printf(e.Title)}type Poem struct { Title string Author string intro string}type ProsePoem struct { Poem Author string}
Poem is declared in the Prosepoem property, which represents the properties and methods that combine poem (properties and methods are inherited).
prosePoem := &ProsePoem{ Poem: Poem{ Title: "Jack", Author: "slow", intro: "simple", }, Author: "test", }
If there is a conflict in the attribute, the perimeter is the primary, that is, it is overwritten.
type ProsePoem struct { Poem Author string}
When accessing author, the default is Prosepoem author, if you need to access the Author property of poem You can use the
ProsePoem.Poem.Author to access the method similarly .
prosePoem := &ProsePoem{}prosePoem.Author = "Shelley"prosePoem.Poem.Author = "Heine"fmt.Println(prosePoem)
This can be seen intuitively from the output.
&{{ Heine } Shelley}
4.5 Interface
Golang's interface is a collection of methods and also a type
package mainimport "fmt"type Animal interface { Speak() string}type Cat struct{}func (c Cat) Speak() string { return "cat"}type Dog struct{}func (d Dog) Speak() string { return "dog"}func Test(params interface{}) { fmt.Println(params)}func main() { animals := []Animal{Cat{}, Dog{}} for _, animal := range animals { fmt.Println(animal.Speak()) } Test("string") Test(123) Test(true)}
As shown above, the struct is assigned a value to the interface variable, and the actual effect is that interface obtains a collection of implementations of the methods in the struct.
4.6 Assertions and Reflections
Assertion is the type of the pre-confirmed variable
func main() { v := "hello world" fmt.Println(typeof(v))}func typeof(v interface{}) string { switch t := v.(type) { case int: return "int" case float64: return "float64" //... etc default: _ = t return "unknown" }}
Reflection is the type of the variable that can be extracted because the type of the stored object is actually recorded in the interface.
import ( "reflect" "fmt")func main() { v := "hello world" fmt.Println(typeof(v))}func typeof(v interface{}) string { return reflect.TypeOf(v).String()}
4.7 Recovery Process
In Golang, the defer code block adds a function call to the function call list. This function call is not a normal function call, but instead adds a function call after the function returns, that is, return. Therefore, defer is often used to release function internal variables.
The following example
func CopyFile(dstName, srcName string) (written int64, err error) {src, err := os.Open(srcName)if err != nil {return}defer src.Close()dst, err := os.Create(dstName)if err != nil {return}defer dst.Close()return io.Copy(dst, src)}
With defer, we can gracefully close/clean the variables used in the code. Defer, as a feature of Golang cleanup variables, has its own unique and unambiguous behavior. The following are defer three usage rules.
- When defer is declared, its parameters are parsed in real time.
That is, the variable value of the defer parameter, the position change after the defer is used in the code does not change the value defer used.
- Defer execution order for advanced back-out
In the function, the first defined defer will be executed after the
- Defer can read a well-known return value
The scope of the defer code block is still within the function, so defer can still read the variables inside the function
The difference between 4.8 make and new
The role of new is to initialize a pointer to a type (*T), which is initialized for Slice,map or Chan and returns a reference (T).
4.9 Exception Handling
For exception handling, Golang provides recover and panic.
The following example
package main import ( "fmt") func main() { defer func() { fmt.Println("1") }() defer func() { if err := recover(); err != nil { fmt.Println(err) } }() panic("fault") fmt.Println("2")} 运行结果:fault1
The program runs panic first, fails, jumps to the defer function that contains recover (), recover captures panic, and panic does not continue to pass. However, after recover, the program will not return to panic that point to continue to perform subsequent actions, but at the recover point continues to perform the subsequent action, that is, the above defer function, Output 1.
Using recover to process panic instructions, you must use defer to declare before panic, otherwise panic cannot capture recover when panic is not able to prevent panic from spreading.
4.10 Co-process
Several concepts of Go scheduling:
M: Kernel thread;
G:go routine, the smallest logical unit of concurrency, created by programmers;
P: Processor, execute G's context, each p will maintain a local go routine queue;
Image.png
In addition to having a local go routine queue for each p, there is a global go routine queue.
Specific scheduling principle:
- The number of p in the initialization is determined by the Gomaxprocs;
- All we have to do is add g;
- The number of G exceeds the processing capacity of M, and there is free p, the runtime will automatically create a new m;
- M get p before work, take the Order of G: Local Queue > Global queue > Other P's queue, if all queues are not available g,m will return p and go to sleep;
A G if a blocking event is blocked, such as:
Image.png
G Context Switch condition occurs:
- system calls;
- Read and write channel;
- Gosched actively give up, will throw G into the global queue;
For example, when a G is blocked, M0 yields p, and the M1 takes over its task queue; When the M0 execution of the blocking call returns, and then throws the G0 to the global queue, he goes to sleep (no p is unable to work);
4.11 Package Management
4.12 Release
5. Contact information
Incorrect documentation can be sent to the mailbox xiyanxiyan10@hotmail.com correction supplement.