Variable length parameters
GO allows a function to take any number of values as parameters. GO has built-in **...Operators can only be used at the last formal parameter of the function...** operator, you must pay attention to the following things when using it:
- The variable length parameter must be at the last of the function list;
- When variable length parameters are parsed as slices, it is
nil
slice - The variable length parameter must be the same type
func test(a int, b ...int){ return }
Since our function can receive variable length parameters, we can also pass slices when passing parameters using **...** for unpacking and converting them into parameter list.append
The method is the best example:
var sl []int sl = append(sl, 1) sl = append(sl, sl...)
The append method is defined as follows:
// slice = append(slice, elem1, elem2) // slice = append(slice, anotherSlice...) func append(slice []Type, elems ...Type) []Type
Declare an indefinite length array
Arrays have fixed lengths. When declaring an array, we must declare the length, because the array must confirm its length when compiling. However, sometimes for me who want to be lazy, I just don’t want to write the length of the array. Is there any way for him to calculate it by himself? Of course, when declaring an array using the **...** operator, you just fill in the element value and leave the others to the compiler itself;
a := [...]int{1, 3, 5} // The length of the array is 3, equivalent to a := [3]{1, 3, 5}
Sometimes we want to declare a large array, but someindex
If you want to set special values, you can also use the **...** operator:
a := [...]int{1: 20, 999: 10} // The length of the array is 100, the element value of subscript 1 is 20, the element value of subscript 999 is 10, and the other element values are 0
init
function
GO language provides precedentmain
Function executioninit
Function, will be automatically executed after initializing each package.init
Functions, each package can have multipleinit
Functions, there can also be multiple source files in each package.init
The loading order of functions is as follows:
Starting from the current package, if the current package contains multiple dependent packages, the dependent package is initialized first, and each package is initialized recursively. In each package, it is executed from front to back according to the dictionary order of the source file. In each source file, constants and variables are initialized first, and finally initialized
init
Function, when multipleinit
When the function is executed in sequence from front to back. After each package is loaded, it returns recursively, and finally initializes the current package!
init
The function is implemented, no matter how many times the package is imported,
init
The function will be executed only once, so useinit
It can be used in service registration, middleware initialization, singleton mode implementation, etc., such as the ones we often usepprof
He used the toolinit
Function, ininit
Routing registration is performed in the function:
//go/1.15.7/libexec/src/cmd/trace/ func init() { ("/io", serveSVGProfile(pprofByGoroutine(computePprofIO))) ("/block", serveSVGProfile(pprofByGoroutine(computePprofBlock))) ("/syscall", serveSVGProfile(pprofByGoroutine(computePprofSyscall))) ("/sched", serveSVGProfile(pprofByGoroutine(computePprofSched))) ("/regionio", serveSVGProfile(pprofByRegion(computePprofIO))) ("/regionblock", serveSVGProfile(pprofByRegion(computePprofBlock))) ("/regionsyscall", serveSVGProfile(pprofByRegion(computePprofSyscall))) ("/regionsched", serveSVGProfile(pprofByRegion(computePprofSched))) }
Ignore the guide packet
Go language has a clean code obsession with designers, so they should avoid code abuse as much as possible in design, so the GO language guide package must be used. If the guide package is not used, it will cause compilation errors. However, in some scenarios, we will encounter situations where we only want to guide packages but not use them, such as the one mentioned above.init
Function, we just want to initialize the packageinit
Function, but will not use any method in the package, you can use it_Operator symbol rename imports an unused package:
import _ "/asong"
Ignore fields
In our daily development, we usually pile up shit on shit, and we will reuse it directly when we encounter a method that can be used. However, we may not use all the return values of this method. We also rack our brains to think of a name for them. Is there any way to not deal with the return values you don’t need to deal with? Of course, there is, or_Operator, assign unnecessary values to empty identifiers:
_, ok := test(a, b int)
json serialization ignores a field
We will be right for most business scenariosstruct
Do serialization operations, but sometimes we wantjson
Some fields inside do not participate in serialization. The **-** operator can help us handle it. The GO structure provides label function and is used in the structure label.-The operator can perform special processing on fields that do not require serialization, using the following:
type Person struct{ name string `json:"-"` age string `json: "age"` }
json serialization ignores empty value fields
We useSerialization will not be ignored
struct
null value in, default output field type zero value (string
The zero value of type is "", and the zero value of object type isnil
...), if we want to ignore these fields without values in serialization, we can add them in the structure labelomitempty
tag:
type User struct { Name string `json:"name"` Email string `json:"email,omitempty"` Age int `json: "age"` } func test() { u1 := User{ Name: "asong", } b, err := (u1) if err != nil { (" failed, err:%v\n", err) return } ("str:%s\n", b) }
Running results:
str:{"name":"asong","Age":0}
Age
We did not add fieldsomitempty
Tag injson
The serialization result is a null value.email
The fields are ignored;
Short variable declaration
Every time I use a variable, I have to declare the function first. For a lazy person like me, I really don't want to write it because I write it.python
If you are used to writing, can you use it directly without variable declaration in GO? We can usename := expressionThe syntax form of declares and initializes local variables, compared to usingvar
The way of declaration can reduce the steps of declaration:
var a int = 10 etc. a := 10
There are two comments when declaring short variables:
- Short variable declarations can only be used within functions and cannot be used to initialize global variables.
- Short variable declaration means introducing a new variable, and variables cannot be declared repeatedly in the same scope.
- If one of the variables in a multivariate declaration is a new variable, then a short variable declaration can be used, otherwise the variable cannot be declared repeatedly;
Type Assertion
We usually useinterface
, one is with a methodinterface
, one is emptyinterface
,Go1.18
There were no generics before, so we can use empty onesinterface{}
To be used as a pseudogenetic when we use the empty oneinterface{}
When used as an entry parameter or return value, type assertions will be used to obtain the types we need. The syntax format of type assertions in Go language is as follows:
value, ok := x.(T) or value := x.(T)
x isinterface
Type, T is a specific type, the first is a safe assertion, and the second is a failure of the assertion, panic will trigger; here type assertions need to be distinguishedx
type, ifx
It is an empty interface type:
The empty interface type assertion is essentially toeface
middle_type
Compare with the type to match, successfully assemble the return value in memory, and directly clear the register if the match fails, return the default value.
ifx
Yes, non-empty interface types:
The essence of non-empty interface type assertion is in iface*itab
Comparison.*itab
A successful match will assemble the return value in memory. If the matching fails, the register will be cleared and the default value will be returned.
Slice loop
Slices/arrays are operations we use frequently and are provided in the GO languagefor range
Syntax to quickly iterate objects, arrays, slices, strings, maps, channels, etc. can all be traversed. In summary, there are three ways:
// Method 1: Only traverse and do not care about data, suitable for slices, arrays, strings, maps, channelsfor range T {} // Method 2: traversal to get the index or array, slice, array and string are index, map is key, channel is datafor key := range T{} // Method 3: traversal to obtain index and data, which is suitable for slices, arrays, and strings. The first parameter is the index, the second parameter is the corresponding element value, the first parameter is the key, and the second parameter is the corresponding value;for key, value := range T{}
Determine whether the map key exists
Go language provides syntaxvalue, ok := m[key]
Let's judgemap
In-housekey
Whether it exists, if it exists, it will return the value corresponding to the key, and if it does not exist, it will return the empty value:
import "fmt" func main() { dict := map[string]int{"asong": 1} if value, ok := dict["asong"]; ok { (value) } else { ("key:asong does not exist") } }
Select control structure
GO language providesselect
Keywords,select
Cooperatechannel
CanGoroutine
Waiting for multiple simultaneouslychannel
Read or write, inchannel
Before the state changes,select
It will block the current thread orGoroutine
. Let’s take a look at an example:
func fibonacci(ch chan int, done chan struct{}) { x, y := 0, 1 for { select { case ch <- x: x, y = y, x+y case <-done: ("over") return } } } func main() { ch := make(chan int) done := make(chan struct{}) go func() { for i := 0; i < 10; i++ { (<-ch) } done <- struct{}{} }() fibonacci(ch, done) }
select
andswitch
Has a similar control structure,switch
The difference is,select
In-housecase
The expression inchannel
The sending and receiving operation, whenselect
Two of themcase
When triggered at the same time, one of them will be executed randomly. Why is it executed randomly? Random introduction is to avoid the occurrence of hunger problems. If we execute them in sequence every time, if twocase
The conditions have always been met, then the next onecase
It will never be executed.
In the above exampleselect
The usage is blocking transmission and reception operation until there is achannel
A state change occurred. We can alsoselect
Used indefault
Statement, thenselect
The statement will encounter these two situations when executing:
- When there is a
Channel
When processing theChannel
Correspondingcase
; - Can be sent and received when it does not exist
Channel
When executingdefault
statements in;
Notice:nil channel
The operation on it will be blocked all the time, if notdefault case
,onlynil channel
ofselect
Will be blocked all the time.
Summarize
This article introduces some development skills in Go, that is, the syntax sugar of Go. Mastering these can improve our development efficiency. Have you learned it?
For more information about Go language development skills and syntax sugar in Go language, please see the relevant links below