variable
-
The init function executes before the main function
func init() { fmt.Println("This is init function") } func main() { fmt.Println("This is main function") } // Output content // This is init function // This is main function
-
The identifier (including constant, variable, type, function name, structure field, etc.) starts with an uppercase letter, so the object using this identifier can be used by the code of the external package (the client needs to import), which is called export
(similar to public in object-oriented); -
If the identifier starts with a lowercase letter, it is not visible outside the package, but it is invisible and available inside the whole package
(similar to private in object-oriented) -
A line represents the end of a statement (it does not need to be ended with a semicolon; it is automatically completed by the compiler)
If you intend to write multiple statements on the same line, you must use; Distinguish (not recommended) -
Number type
type describe int8/int16/int32/int64 Signed integer uint8/uint16/uint32/uint64 Unsigned integer float32/float64 IEEE-754 32/64 bit floating point number complex64/complex128 32 / 64 bit real and imaginary numbers byte Similar to uint8 rune Similar to int32 uint 32 or 64 bit int Same size as uint unitptr Unsigned integer used to hold a pointer -
variable
Global variables and local variables can have the same name, refer to global variable
// Variable declaration var identifier type // 1. Specify the variable type (default value is used if no assignment is made) var v_name v_type var v_name v_type = value // 2. Type derivation var v_name = value // 3. Omit var and declare with: =; Can only be used to declare local variables v_name := value // The definition of: = is correct var outer = true func main() { // a. Variable definitions defined outside the print method fmt.Println(outer) // b. If it is a global variable, it can be redefined (including different types) (fixme should not be the same variable) outer := "use := Redefine variables" fmt.Println(outer) // c. The following definitions cannot be compiled // var inner [string] = "local variable" // fmt.Println(inner) // inner: = "redefining local variables cannot be compiled" // fmt.Println(inner) } // Local variable: multiple variables of the same type // 1. Specify the type (three variables have the same type; they can be global variables) var vname1,vname2,vname3 type vname1,vname2,vname3 = v1, v2, v3 // 2. Type derivation (can be different types; can be global variables; parallel | simultaneous assignment) var vname1,vname2,vname3 = v1, v2, v3 // 3. Initialization declaration (can be of different types; variables must not be declared inside the method; parallel | simultaneous assignment) vname1,vname2,vname3 := v1, v2, v3 // Global variable: multiple variable declarations with different types (only global variables) var ( v_name_1 type1 v_name_2 type2 )
-
Value type and reference type
- Value type
- All basic types such as int, float, bool and string belong to value types. Variables using these types directly point to values in memory
- When the equal sign = is used to assign the value of one variable to another variable, such as j = i, the value of i is actually copied in memory
- You can use & i to get the memory address (addresser) of variable i
- The value of a variable of value type is stored on the stack
- reference type
- More complex data usually needs to use multiple values, and these data are generally saved with reference types
- A reference type variable r1 stores the memory address (number) where the value of r1 is located, or the location of the first value in the memory address (this memory address is also called a pointer)
- Multiple values pointed to by a pointer of the same reference type can be continuous or scattered in memory
- Value type
-
Local variables are forbidden to be declared and not used; Global variables allow only declarations that are not used
var outer string = "Global variables allow only declarations that are not used" func main() { // Unused variable 'inner' var inner = "Local variables are prohibited from being declared and not used" }
-
If you want to simply exchange the values of two variables, you can use a, b=b, a
-
Blank identifier_ It is also used to discard values, such as value 5 in, B: = abandoned in 5 and 7
_ In fact, it is only a writable variable and its value cannot be obtained
(in Go language, you must use all declared variables, but sometimes you don't need to use all the return values from a function) -
Parallel assignment is also used when a function returns multiple return values
val, err = Func1(var1)
constant
-
The data types in constants can only be Boolean, numeric (integer, floating point and complex) and string
-
Define format
// Type descriptors can be omitted const identifier [type] = value // Multiple variables of the same type can be defined at the same time const c_name_1, c_name_2 = value1, value2 // You can define local and global constants with the same name const a1, a2, a3 = "a1", 23, true func method() { // This definition will not report an error const a1, a2 = "aa1", "aa2" // Give priority to the output of local variable definitions. If not, the output of global variable values fmt.Println(a1, a2, a3) }
-
Constants can also be used as enumerations
const ( Unknown = 0 Female = 1 Male = 2 )
-
In the constant definition, len(), cap(), unsafe.Sizeof() can be used to calculate the value of the expression (it must be a built-in function)
const ( a = "abc" b = len(a) c = unsafe.Sizeof(a) )
-
iota, a special constant, can be considered as a constant that can be modified by the compiler
When each const keyword appears, it is reset to 0, and then before the next const appears, the number represented by iota will automatically increase by 1// Definition one const ( a = iota b = iota c = iota ) // Continue with definition 2 // const appears and the value is reset const ( d = iota e = iota f = iota ) // a=0,b=1,c=2 // d=0,e=1,f=2 // Abbreviated as const ( a = iota b c )
-
More complicated usage
// Example 1 const ( a = iota // a=0 b // b=1 c // c=2 d = "ha" // d="ha",iota+=1=3 e // e="ha",iota+=1=4 f = 100 // f=100,,iota+=1=5 g // g=100,,iota+=1=6 h = iota // Recovery count h=7 i // i=8 ) // Example 2 const ( i = 1 << iota // i=1<<0=1 j = 3 << iota // j=3<<1=6 k // k=3<<2=12 l // l=3<<3=24 )
operator
-
Arithmetic operator
Including +, -, *, /,%, + +--
func method() { a := 10 b := 20 var c int c = a + b c = a - b c = a * b c = a / b c = a % b // Equivalent to: a=a+1 a++ // Equivalent to: a=a-1 a-- // There is no operation of + + a or -- a }
-
Relational operator
Including = =,! =, >, <, > =<=
-
Logical operator
Including & &, |!
- No single and, single or
- The style of go is that you don't have to use parentheses to wrap logical operator calculations
func method() { a := true b := true // The style of go is that you don't have to wrap logical operations in parentheses if a || b { fmt.Println("a||b is true") } // There is no single and, single or in the logical operator // if a | b{} }
-
Bitwise Operators
You can operate on the binary bits of integers in memory
Including &, |^
operator explain & And operation, all true is true | Or operation, all false is false ^ XOR operation. The same is false and the different is true << Shift left operator, shift n bits to the left is multiplied by 2 to the nth power (the high bit is discarded and the low bit is supplemented by 0) >> Shift right operator, shift n bits right is divided by 2 to the nth power -
Assignment Operators
operator explain example = Assign the value of an expression to an lvalue C = A + B += Add and assign C += A equals C = C + A -= Subtraction before assignment C -= A equals C = C - A *= Multiply and assign C *= A equals C = C * A /= Divide and assign C /= A equals C = C / A %= Assign value after remainder C% = a equals C = C% a <<= Left shift assignment C < < 2 equals C = C < < 2 >>= Assignment after shift right C > > = 2 equals C = C > > 2 &= Bitwise and post assignment C & = 2 equals C = C & 2 ^= Assignment after bitwise XOR C ^= 2 equals C = C ^ 2 |= Bitwise or post assignment C | 2 equals C = C | 2 -
Other Operators
operator explain example & Variable memory address &var_ Name returns the actual address of the variable *(fixme) Pointer variable *var_name is a pointer variable -
Operator priority (from high to low)
priority operator 7 ^ ! 6 * / % <> & &^ 5 + - | ^ 4 == != < = > 3 <- 2 && 1 ||
Conditional statement
sentence | describe |
---|---|
if statement | An if statement consists of a Boolean expression followed by one or more statements. |
if...else statement | An optional else statement can be used after the if statement. The expression in the else statement is executed when the Boolean expression is false. |
if nested statement | You can embed one or more if or else if statements in an if or else if statement. |
switch statement | switch statements are used to perform different actions based on different conditions. |
select statement | The select statement is similar to the switch statement, but select randomly executes a runnable case. If there is no case to run, it will block until there is a case to run. |
Switch
-
The switch statement executes from top to bottom until a match is found, and there is no need to add a break after the match
-
You can test multiple possible qualified values in one case at the same time, separated by commas
-
All case candidate values must be of the same type as the switch variable (expression) (otherwise, compilation error)
-
There are two ways to write
//Variable var_name can be any type, while val1 and val2 can be any value of the same type switch var_name { case val1: // There is no need to add break in the match ... case val2: // Multiple value s can exist in a case ... default: ... }
Example:
func method() { grade := "B" marks := 90 // Writing method I switch marks { case 90: grade = "A" // case can have multiple values that may meet the conditions at the same time case 80: grade = "B" // break is not required in case default: grade = "C" } // Writing method 2 switch { case grade == "A": fmt.Println("excellent") // case can have multiple values that may meet the conditions at the same time case grade == "B", grade == "C": fmt.Println("good") // break is not required in case default: fmt.Println("difference") } fmt.Println("The grade is: ", grade) }
Type Switch(fixme)
The switch statement can also be used for type switch to determine the type of variable actually stored in an interface variable
switch x.(type){ case type: statement(s) case type: statement(s) /* You can define any number of case s */ default: /* Optional */ statement(s) }
Example:
func method() { // Define interface var x interface{} switch i := x.(type) { case nil: fmt.Printf(" x Type of :%T", i) case int: fmt.Printf("x yes int type") case float64: fmt.Printf("x yes float64 type") // The case item can also be a func case func(int) float64: fmt.Printf("x yes func(int) type") // You can test multiple values that may meet the criteria case bool, string: fmt.Printf("x yes bool or string type") default: fmt.Printf("Unknown type") } }
Select(fixme)
- It is similar to select in the operating system
- It has a similar control structure to switch, but the expressions in these case s must be Channel transceiver operations
- Is a control structure;
- select randomly executes a runnable case;
- If there is no case to run, select will block until there is a case to run;
- The default (if any) must be executed normally
select { case communication clause : statement(s) case communication clause : statement(s) /* You can define any number of case s */ default : /* Optional */ statement(s) }
- Each case must be a Channel
- All Channel expressions are evaluated
- All expressions sent are evaluated
- If any Channel can execute, it will execute; Others ignored
- If there are multiple case s that can be run, select will randomly and fairly select one to execute; Others ignored
- If there is no case to run:
- Default exists, execute default
- No default, blocking until a channel is available (Go will not evaluate the channel or value)
The knowledge points of select are summarized as follows:
- The select statement can only be used for channel read and write operations
- The case condition (non blocking) in select is executed concurrently. Select will select the case condition whose operation is successful first to execute. If multiple conditions return at the same time, one execution will be selected randomly. At this time, the execution order cannot be guaranteed. For a blocked case statement, it will be executed until there are channels available for operation. If there are multiple channels available for operation, one of the cases will be randomly selected for execution
- For the case conditional statement, if there is a read / write operation with the channel value of nil, the branch will be ignored, which can be understood as deleting the case statement from the select statement
- If there is a timeout condition statement, the judgment logic is that if there is no case that meets the condition within this time period, the timeout case will be executed. If an operable case occurs during this period, the case will be executed directly. Timeout statements are generally used instead of default statements
- An empty select {} will cause a deadlock
- For select {} in for, it may also cause excessive cpu consumption
Circular statement
Cycle type | describe |
---|---|
for loop | Repeat statement block |
loop nesting | Nest one or more for loops within a for loop |
Cycle type
for loop
// Of the three forms, only one uses a semicolon // 1. Same as for of C (same as Java, without parentheses) for init; condition; post { } // 2. Same as C's while for condition { } // 3. Same as for(;) of C for { }
The range format of the for loop can iterate over slice, map, array, string, etc
for key, value := range oldMap { newMap[key] = value }
Example:
func method() { numbers := [6]int{1, 2, 3, 5} for i, x := range numbers { fmt.Printf("The first %d position x Value of = %d\n", i, x) } }
Nested loop
// Same as Java, no parentheses for [condition | ( init; condition; increment ) | Range] { for [condition | ( init; condition; increment ) | Range] { statement(s) } statement(s) }
Loop control statement
Control statement | describe |
---|---|
break statement | It is often used to break the current for loop or jump out of the switch statement |
continue statement | Skip the remaining statements of the current loop and proceed to the next loop. |
goto Statement | Transfers control to the marked statement. |
goto (not recommended)
You can unconditionally transfer to the line specified in the process
It is usually used in conjunction with conditional statements to realize conditional transfer, form a loop, jump out of the loop and other functions
goto is generally not recommended to avoid confusing the program flow, making the program difficult to understand or debug
goto label .. . label: statement
Example:
// 1. Terminate nested loop func method1() { for x := 0; x < 10; x++ { for y := 0; y < 10; y++ { if y == 2 { // Jump to the label (it will also terminate all loops, which is a bit similar to the use of label in Java) goto breakHere // Direct use will only exit the current cycle // break } } } // Manual return to avoid entering the label return // label breakHere: fmt.Println("done") } // 2. Code reuse func method2() { err := firstCheckError() if err != nil { goto onExit } err = secondCheckError() if err != nil { goto onExit } fmt.Println("done") return onExit: fmt.Println(err) exitProcess() }
function
- The most basic code block used to perform a task
- There is at least one main function
- Logically, each function performs the specified task
- Function name, parameter list and return value (type, number and order) together constitute the function signature
- The standard library provides a variety of available built-in functions (existing in the builtin and unsafe standard libraries)
- Return value: fixme
definition:
// 1. Multiple values can be returned // 2. If there is no return value, return_types can be defaulted // 3. The input parameter types are the same, and simple definitions can be used func function_name( [parameter list] ) [return_types] { // function body } func function_name( [parameter list] ) (type1,type2,...,typeN) { // function body } func max(a, b int) int { // Method body omission return ret } func swap(x, y string) (string, string) { return y, x }
Function parameters
Delivery type | describe |
---|---|
pass by value | Value passing refers to copying and passing a copy of the actual parameters to the function when calling the function, so that if the parameters are modified in the function, the actual parameters will not be affected. |
Reference passing | Reference passing refers to passing the address of the actual parameter to the function when calling the function. The modification of the parameter in the function will affect the actual parameter. |
By default, the Go language uses value passing, that is, the actual parameters will not be affected during the call
An example of reference passing (specific usage to be studied):
// The reference passed into the body of the reference method is different func swap(x *int, y *int) { var tmp int tmp = *x *x = *y *y = tmp }
Function usage
Function usage | describe |
---|---|
Function as value | Functions can be used as values after they are defined |
closure | Closures are anonymous functions that can be used in dynamic programming |
method | A method is a function that contains the recipient |
/* Declare function variables */ getSquareRoot := func(x float64) float64 { return math.Sqrt(x) } /* closure */ func getSequence() func() int { i := 0 return func() int { i += 1 return i } } /* Function method */ func (variable_name variable_data_type) function_name([var_name type]) [return_type]{ /* Function body*/ }
Function method: equivalent to a custom method owned by a class in Java
/* Define function fixme */ type Circle struct { radius float64 } // The method belongs to a method in an object of type Circle func (c Circle) getArea() float64 { //c.radius is an attribute in an object of type Circle return 3.14 * c.radius * c.radius } // The method definition is correct, but it is not a method of an object of type Circle func getArea2(c Circle) float64 { return math.Pi * c.radius * c.radius } // Method can receive input parameters func (c Circle) getPerimeter(x, y int) float64 { fmt.Println("x=", x, ",y=", y) return math.Pi * c.radius * 2 } func main() { var c1 Circle c1.radius = 10.00 // Method call fmt.Println("Area of Circle(c1) = ", c1.getArea()) // getArea2 is not a method of a Circle class object // fmt.Println("Area of Circle(c1) = ", c1.getArea2()) area := getArea2(c1) fmt.Println("area = ", area) fmt.Println("Perimeter of Circle(c1) = ", c1.getPerimeter(10, 15)) }
Variable scope
Variables can be declared in three places:
- Variables defined in a function are called local variables
- Variables defined outside the function are called global variables
- Variables in a function definition are called formal parameters
local variable
- Declare in function body
- The scope is only in the function body
- Parameters and return value variables are also local variables
global variable
- Declaration outside the function
- It can be used in the whole package or even external packages (after being exported)
The names of global variables and local variables can be the same, but the local variables in the function will take precedence
Formal parameter (formal parameter)
Variables that appear in the function / method parameter table (used as local variables)
Initialize local and global variables
data type | Initialize defaults |
---|---|
int | 0 |
float32 | 0 |
pointer(fixme) | nil |
array
// statement var variable_name [SIZE] variable_type // initialization // SIZE can not be written (brackets must be reserved), and will be automatically pushed to and set according to the number of values var variable_name = [SIZE]variable_type{val_1,val_2,...,val_SIZE} var variable_name = []variable_type{val_1,val_2,...,val_SIZE} // Visit strategy // Example var balance [10] float32 balance := []int{1, 2, 5, 7, 8, 9, 3} balance := [10]int{1, 2, 5, 7, 8, 9, 3}
Traverse reference [for loop] (#for loop)
A definition or reference that does not specify a length is actually Slice
Multidimensional array
// statement var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type // Example (2D array) var a1 [3][4] int var a2 = [3][4]int{ {0, 1, 2, 3}, /* The first row index is 0 */ {4, 5, 6, 7}, /* The index of the second row is 1 */ {8, 9, 10, 11}, /* The third row has an index of 2 */ }
Function transfer value
As a formal parameter, the length of the parameter array must be consistent with the passed in array (fixme array and slice distinguish???)
func method(arr [SIZE]type) [return_types] {} func method(arr []type) [return_types] {}
Pointer (fixme)
Pointer variable: memory address pointing to the value
- The assignment must be the memory address of the corresponding variable, that is, PTR = & var_ name
- Add a * sign (prefix) before the pointer type to get the content pointed to by the pointer
Pointer declaration:
var var_name *var_type // Example var ip *int /* Pointing integer */ var fp *float32 /* Point to floating point */
use:
func method() { a := 201 /* Declare actual variables */ var ip *int /* Declare pointer variables */ ip = &a /* Storage address of pointer variable */ // ip = a / * error declaration*/ fmt.Printf("variable a The memory address is: %x\n", &a) /* Use a pointer to access the value stored at the destination memory address */ fmt.Printf("*ip Value of variable: %d\n", *ip) fmt.Printf("ip Value of variable: %d\n", ip) } // Output results // The memory address of variable a is c00000aa058 // *Value of ip variable: 201 // Value of ip variable: 824634417240
Null pointer
-
When a pointer is defined and not assigned to any variable, its value is nil, that is, a null pointer.
-
Conceptually, nil, like null, None, nil and null in other languages, refers to zero value or null value.
-
Pointer variables are usually abbreviated to ptr.
Null pointer judgment:
ptr == nil ptr != nil
Pointer array
Declaration method:
var ptr [SIZE]*type // Example: integer pointer array var ptr [5]*int
Pointer to pointer
A pointer variable stores the address of another pointer variable
Declaration method:
var ptr **type // Example var ptr **int
Two * signs are required to access the pointer variable value pointing to the pointer
func method() { a := 3000 var ptr *int var pptr **int /* Pointer ptr address */ ptr = &a /* Pointer ptr address */ pptr = &ptr /* Gets the value of pptr */ fmt.Printf("variable a = %d\n", a) fmt.Printf("Pointer variable *ptr = %d\n", *ptr) fmt.Printf("Pointer variable to pointer **pptr = %d\n", **pptr) }
Pointer as parameter
func method(x, y *var_type) { // The internal use of fixme needs to meet the * x *y format (all corresponding values are operated through the memory address) }
structural morphology
A collection of data (similar to a class in Java) consisting of a series of data of the same or different types
Declaration method:
// Structure declaration type struct_variable_type struct { member definition member definition ... member definition } // Structure variable declaration var variable_name struct_variable_type variable_name := structure_variable_type {value1, value2...valueN}
Use the dot (.) operator to access structure members. The format is: "structure. Member name"
// definition type Books struct { title string author string subject string bookId int } // variable var book1 Books book2 := Books{ title: "Go language", author: "www.w3cschool.cn", subject: "Go Language course", bookId: 1, } // Property access book2.title
Structure pointer
// Pointer definition var struct_pointer *struct_variable_type // The use method is the same as above var structPointer *Books structPointer = &book2 fmt.Println(structPointer.author)
Slice
-
Slicing is an abstraction of arrays
-
The length of the slice is not fixed. It supports additional elements and dynamic capacity expansion (the length of the array is not variable, and the slice is to solve this problem)
-
Before the slice is initialized, it defaults to nil. At this time: len=cap=0
-
append() and copy(): append and copy
// statement // 1. General declaration var identifier []type // 2. Declare with make() var identifier []type = make([]type, len) // 3. make() declaration abbreviation identifier := make([]type, len [,cap]) // fixme specifies the capacity (length is the length of the array and the initial length of the slice; capacity is optional) make([]T, length [,capacity]) // Initialization (the following are sample abbreviations) var slice_var = []type{val1,val2,...,valN} slice_var := []type{val1,val2,...,valN} slice_var_1 := slice_var[:] // slice_var is a slice reference slice_var_2 := slice_var // It seems OK to write so slice_var_3 := slice_var[startIndexInclude:endIndexExclude] // Slice (array) interception slice_var_4 := slice_var[startIndexInclude:] // Slice (array) interception slice_var_5 := slice_var[:endIndexExclude] // Slice (array) interception // Element append numbers = append(numbers, 1,2,3,4) // Copy copy(numbers1,numbers)
Language range
range keyword is used to iterate over elements such as array, slice, linked list channel or set map in the for loop
Personal understanding: use the for loop to traverse a keyword used in an array, slice, linked list or collection
Range expression | First value | Second value [optional] |
---|---|---|
Array or slice a [n]E | Index i int | a[i] E |
String s string type | Index i int | rune int |
map m map[K]V | Key k K | Value m[k] V |
channel c chan E | Element e E | none |
// When iterating over a string, index is the index and value is the character (Unicode value) for index|key, value := array|slice|channel|map|string { // Business code }
Map
- Using hash implementation, it is an unordered set of key value pairs
- If the map is not initialized, the map is a nil map
- nil map cannot write key value pairs
After making (), you can write again - The make method cannot be used independently. You need to use fixme together: what does the make function mean??
- Determine whether the element exists in the map
/* Declare variables. The default map is nil */ var map_variable map[key_data_type]value_data_type /* Using the make function */ map_variable = make(map[key_data_type]value_data_type) // Determine whether the key exists in the map // If exists=true, then value is the corresponding value value, exists := map_variable[key] // Delete element delete(map_variable, key)
Recursive function
Type conversion
- Converts a variable of one data type to a variable of another type
- Implicit type conversion is not supported
// type_name is the type and expression is the expression type_name(expression) i := 32 float32(i) //var a int32 = 3 //var b int64 //b = a //fmt.Printf("b is:% d", b)
Interface
- Define keyword interface
- You don't have to implement all methods
/* Define interface */ type interface_name interface { method_name1(ps param_struct) [return_type] method_name2() [return_type] ... method_namen [return_type] } /* Define parameter structure */ type param_struct struct { /* variables */ } /* Define implementation classes */ type struct_impl struct { /* variables */ } /* Implementation interface method */ func (struct_impl_variable struct_impl) method_name1(ps param_struct) [return_type] { /* Method implementation */ } ... func (struct_impl_variable struct_impl) method_namen() [return_type] { /* Method implementation*/ } // Method call var in interface_name // TODO has a new keyword here in = new(struct_impl) in.method_name2()
Example:
// parameter type Food struct { id int name string } // Interface type Animal interface { eat(food Food) bool } // Implementation class type Dog struct { id int32 name string } // Method implementation func (dog Dog) eat(food Food) bool { fmt.Println(dog.name, "eating", food.name) return true } // call func main() { // Input parameter food := Food{ id: 1, name: "Bone", } // Method call 1 (using the new keyword to create an object fixe is equivalent to Java's parameterless construction?) dog1 := new(Dog) dog1.name = "Dog" dog1.id = 233 dog1.eat(food) // Method call two dog2 := Dog{ id: 1, name: "Jacky", } dog2.eat(food) }
error handling
- It provides a very simple error handling mechanism through the built-in error interface
- Usually, an error message is returned in the last return value of the function (which can be generated using errors.New)
reference material: