This is the fifth day of my participation in the August More text Challenge. For details, see: August More Text Challenge
5. The function
5.1 Defining Formats
Functions form the logical structure of code execution.
In THE Go language, functions are basically composed of the keyword func, function name, parameter list, return value, function body, and return statement.
Go functions are defined in the following format:
Func FuncName(/* argument list */) (o1 type1, o2 type2/* return type */) {// return v1, v2 // return multiple values}Copy the code
Function definition:
- Func: Functions are declared beginning with the keyword func
- FuncName: The name of a function. By convention, a function name with a lowercase letter is private and a uppercase letter is public
- Parameter list: The function can have 0 or more parameters in the format of variable name type. If multiple parameters are separated by commas (,), default parameters are not supported
- Return type:
- The above return value declares two variable names o1 and O2 (named return parameter). This is not required. It is possible to have only type but no variable name
- If there is only one return value and no return value variable is declared, then you can omit the parentheses that include the return value
- If there is no return value, then the final return information is simply omitted
- If there is a return value, then you must add a return statement inside the function
5.2 Custom Functions
5.2.1 No Parameter No return value
Println("this is a Test func")} func main() {Test() // Function call with no parameters and no return value}Copy the code
5.2.2 Return value if no parameter is used
5.2.2.1 Common Parameter List
Printf("v1 = %d, v2 = %d\n", v1, v2)} func Test02(v1, v2 int) {func Test01(v1, v2 int) { Printf("v1 = %d, v2 = %d\n", v1, v2)} func main() {Test01(10, 20) // Test02(11, 22)Copy the code
5.2.2.2 Undetermined Parameter List
- Indeterminate parameter type
An indefinite parameter is a function that passes in an indefinite number of parameters.
To do this, we first need to define the function to accept indefinite parameter types:
/ / like... Func Test(args...) func Test(args...) func Test(args... Int) {for _, n := range args {// iterate over the argument list fmt.println (n)}} func main() {// Function call, Test(1) Test(1, 2, 3, 4)}Copy the code
- The passing of indeterminate parameters
func MyFunc01(args ... Int) {FMT.Println("MyFunc01") for _, n := range args {// iterate over FMT.Println(n)}} func MyFunc02(args... Int) {FMT.Println("MyFunc02") for _, n := range args {// iterate over FMT.Println(n)}} func Test(args... int) { MyFunc01(args...) MyFunc01 MyFunc02(args[1:]...) MyFunc02(args[1:]...) MyFunc02} func main() {Test(1, 2, 3) // Function call}Copy the code
- Multiple parameters of inconsistent types
import "fmt"
func MyPrintf(args ...interface{}) {
for _, arg := range args {
switch arg.(type) {
case int:
fmt.Println(arg, "is an int value.")
case string:
fmt.Println(arg, "is a string value.")
case int64:
fmt.Println(arg, "is an int64 value.")
default:
fmt.Println(arg, "is an unknown type.")
}
}
}
func main() {
var v1 int = 1
var v2 int64 = 234
var v3 string = "hello"
var v4 float32 = 1.234
MyPrintf(v1, v2, v3, v4)
}
Copy the code
5.2.3 No parameter Has a return value
If a function has a return value, it must have an explicit termination statement, otherwise a compilation error will be raised.
A return value
Func Test01() int {// mode 1 return 250} It's better to name the return value, because you don't name the return value, which makes your code a little bit cleaner, Func Test02() (value int) {func Test03() (value int) {func Test03() (value int) {func Test03() (value int) { Value = 250 return} func main() {v1 := Test01() // Function call v2 := Test02() // Function call v3 := Test03() // Function call fmt.Printf("v1 = %d, v2 = %d, v3 = %d\n", v1, v2, v3) }Copy the code
5.2.3.2 Multiple Return Values
Func Test01() (int, string) {return 250, "sb"} func Test02() (a int, STR string) { A = 250 STR = "sb" return} func main() {v1, v2 := Test01(), v3 := Test02() Printf("v1 = %d, v2 = %s, v3 = %s, v4 = %d\n", v1, v2, v3, v4)}Copy the code
5.2.4 Return value with parameters
Func MinAndMax(num1 int, num2 int) (min int, num2 int) Max int) {if num1 > num2 {min = num2 Max = num1} else {Max = num2 min = num1} return} func main() { min, max := MinAndMax(33, 22) fmt.Printf("min = %d, max = %d\n", min, max) //min = 22, max = 33 }Copy the code
5.3 Recursive functions
Recursion means that a function can call itself directly or indirectly.
Recursive functions usually have the same structure: a jump condition and a recursive body. The jump condition is the argument passed in to determine whether the recursion needs to be stopped, and the recursion body is something that the function itself does.
Function call order:
Just like C, it’s a stack. The called person executes first.
For example, if the three functions ABC are called in the order C- >B- >A, A will be executed first.
Again, recursion is calling itself, assuming 3- >2- >1, it will print 1 first.
// Loop 1+2+3... +100 func Test01() int { i := 1 sum := 0 for i = 1; i <= 100; I ++ {sum += I} return sum} +100 func Test02(num int) int {if num == 1 {return 1} return num + Test02(num-1)} +100 func Test03(num int) int {if num == 100 {return 100} return num+ Test03(num+1)} func main() { fmt.Println(Test01()) //5050 fmt.Println(Test02(100)) //5050 fmt.Println(Test03(1)) //5050 }Copy the code
5.4 Function Types
In Go, a function is also a data type. We can define it by type. Its type is all the types that have the same parameters and the same return value. Similar to overwrite (overwrite of the same name).
Callback function: A function that takes a parameter of the function type is called a callback function.
More precisely, passing a pointer to one function as an argument to another. The definition of a callback function is not called directly by the implementer of the function, but is called by another party when a particular event or condition occurs, in response to that event or condition.
Type FuncType func(int, int) int = funcc (int, int) int = funcc F FuncType, function type, function type, function type, function type, function type, function type, function type, function type, function type, function type, function type, function type, function type Func Calc(a, b int, f FuncType) (result int) {result = f(a, b)} func Add(a, b) B int) int {return a + b} func Minus(a, b int) int {return a -b} func main() {return a -b} func main() { Result := Calc(1, 1, Add) fmt.Println(result) //2 var f FuncType = Minus fmt.Println("result = ", f(10, 2)) //result = 8 }Copy the code
5.5 Anonymous functions and closures
A closure is when a function “captures” other constants and variables in the same scope as it. This means that when the closure is called, no matter where in the program it is called, it can use these constants or variables. It doesn’t care if the captured variables and constants are out of scope, so they remain as long as the closure is still in use.
In Go, all anonymous functions (called function literals in the Go specification) are closures. Anonymous functions, which are functions implemented without the need to define their names, are not a new concept, dating back to Lisp in 1958.
Func main() {I := 0 STR := "mike" f1 := func() {" func main() {I := 0 STR := "mike" I = %d, STR = %s\n", I, STR)} f1() Var f2 FuncType = f1 f2() var f3 FuncType = func() {fmt.printf (" 模 式2: I = %d, STR = %s\n", I, STR)} f3() // func() {// anonymous function, no parameter, no return value FMT. I = % d, STR = % s \ n ", I, STR)} () / / don't forget the back of the (), () is used, the direct call this anonymous function / / 4, anonymous functions, V := func(a, b int) (result int) {result = a + b return}(1, 1) Println("v = ", v)}Copy the code
Closures capture the characteristics of external variables:
Func main() {I := 10 STR := "mike" func() {I = 100 STR = "go" // inside: I = 100, STR = go fmt.printf (" inside: I = %d, STR = %s\n", I, STR)}() I = %d, STR = %s\n", I, STR)}() I = %d, STR = %s\n", I, STR)} functions return anonymous functions: // squares return an anonymous function, func() int // This anonymous function returns the square of the next number each time it is called. Func squares() func() int {var x int return func() int {var x int return func() int {// anonymous function x++ // Capture external variable return x * x}} func main() {f := squares() fmt.Println(f()) // "1" fmt.Println(f()) // "4" fmt.Println(f()) // "9" fmt.Println(f()) // "16" }Copy the code
The squares function returns another function of type func() int. A call to squares generates a local variable x and returns an anonymous function. Each time an anonymous function is called, it increments the value of x by 1 and then returns the square of x. The second time squares is called, a second X variable is generated and a new anonymous function is returned. The new anonymous function operates on the second x variable.
From this example, we see that the life cycle of a variable is not determined by its scope: x still exists implicitly in f after squares returns.
5.6 the closure
Closures, it’s a little harder to understand. First, a few concepts. When a function call ends, all local variables are freed, except for the return value. Function A defines function B, so the outside of function B is called the outside function, and the inside function is called the inside function, if the outside function has A temporary variable A, and the inside function has A temporary variable B. In this case, if the inner function uses a and the return value of a is a reference to B, the closure is called. Such as:
Import "FMT" // function A func add_function_generator(I, j int) int { Also called closure a := func(I, J int) (sum int) {sum = I + j return}(I,j) return a} func main() {a := add_function_generator(1,1) fmt.Println("a = ", a) }Copy the code
In general, in our understanding, if a function ends, everything inside the function is freed, returned to memory, and the local variables disappear. But closures are a special case. If the outer function ends up with a temporary variable of its own that will be used in the inner function, it binds the temporary variable to the inner function and then closes itself. Such as:
Package main // Must import "FMT" // The return value of the function is an anonymous function that returns a function type // The anonymous function returns the square of the next number each time it is called. Func squares() func() int {// x allocates space only when the function is called, Var x int return func() int {x++ return x * x}} func test(){f := squares() fmt.println (f()) //1 FMT.Println(f()) //4 FMT.Println(f()) //9 FMT.Println(f()) //16 FMT.Println(f()) //25 } func main() {func main() {return x * x {var x int () {return x * x ()} func main() {return x * x (); Returns a function type, called anonymously by f, which calls the closure function. It doesn't care if the captured variables and constants are out of scope, so the variables will exist as long as the closure is still in use. test() f := squares() fmt.Println(f()) //1 fmt.Println(test01())//1 fmt.Println(test01())//1 fmt.Println(test01())//1 fmt.Println(test01())//1 }Copy the code
Essentially, just as with macro substitution, replacing the body of the function inside the closure with the body of the outer function would look like this:
Func test(){var res int Var x int x++ res = x * x fmt.println (res) x++ res = x * x fmt.println (res) x++ res = x * x fmt.println (res) x++ res = x * x fmt.println (res) x++ res = x * x fmt.println (res) x++ res = x * x fmt.println (res) x++ res = x * x fmt.println (res) x++ Res = x * x FMT.Println(res)Copy the code
5.6 Defer the call
5.6.1 defer action
The keyword defer is used to postpone the execution of a function or method (or the anonymous function currently created). Note that the defer statement can only appear inside a function or method.
Func main() {Println("this is a test") defer Println("this is a test") // this is a test this is a defer */ }Copy the code
The defer statement is often used to handle paired operations such as open, close, connect, disconnect, lock, and release. With the defer mechanism, no matter how complex the function logic is, the resource is guaranteed to be released on any execution path. The defer that releases the resource should follow directly after the statement that requested the resource.
5.6.2 Execution sequence of multiple Defer
If there are multiple defer statements in a function, they will be executed in LIFO (last in, first out) order. Even if a function or one of the delayed calls goes wrong, these calls are still executed.
Func test(x int) {FMT.Println(100 /x) } func main() {defer fmt.println ("aaaaaaaa") defer fmt.println (" BBBBBBBB ") defer test(0) defer Println(" CCCCCCCC ") /* Run: CCCCCCCC BBBBBBBB aaaaaaaa Panic: Runtime error: INTEGER divide by zero */}Copy the code
Use 5.6.3 defer in combination with the anonymous function
Func main() {a, b := 10, 20 defer func(x int) {// a pass to x FMT.Println("defer:", x, Printf("a = %d, b = %d\n", a, b) /* Result: a = 20, b = 120 defer: 10 120 */}Copy the code
5.6.4 Which is first — defer or return
Var name string = "go" func myfunc() string {defer func() {name = "python"}() fmt.printf ("myfunc ") %s\n", name) return name} func main() {myname := myfunc() FMT.Printf(" name in the main function: %s\n", name) FMT.Println(" myname: ", myname)}Copy the code
Myfunc (name: go); python (name: go)
Defer is called after the return. So before executing defer, myName has been assigned to go.
5.7 Obtaining Command Line Parameters
Package main import (" FMT "" OS" // the package required by os.args) func main() {Args := os.args // Get all the parameters entered by the user / / if the user has no input, or the number of parameters is not enough, then call the function prompt the user if the args = = nil | | len (args) < 2 {FMT. Println (" err: Printf(" IP = %s, port = %s\n", IP, "port = %s\n", IP," port = %s\n") return} IP := args[1] port) }Copy the code
5.8 scope
Scope is the scope in source code of a constant, type, variable, function, or package represented by a declared identifier.
Variables defined within a function are called local variables. Variables defined outside a function are called global variables. Variables with the same name can be declared in different scopes. The access principle is as follows: in the same scope, the nearest variable is accessed. If there is no such variable declared in this scope, the global variable is accessed.
5.8.1 Local variables
Variables, arguments, and return variables declared in the body of a function are local variables whose scope is limited to the body of the function:
func test(a, b int) { var c int a, b, c = 1, 2, 3 fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c) } func main() { //a, {var I int I = 10 fmt.Printf(" I = %d\n", I)} // I = 20 //err, I does not belong to the scope if a := 3; A == 3 {FMT.Println("a = ", a)} //a = 4 //err, a only if internal use}Copy the code
5.8.2 Global variables
Variables declared outside the body of a function are called global variables. Global variables can be used throughout the package or even outside the package (after being exported).
Func main() {a = 10 fmt.printf ("main a = %d\n", a)} func main() {a = 10 fmt.printf ("main a = %d\n", a)} func main() {a = 10 fmT.printf ("main a = %d\n", a); a) //main a = 10 test() //test a = 10 }Copy the code
5.8.3 Variables with the same name in different scopes
Variables with the same name can be declared in different scopes. The access principle is as follows: in the same scope, the nearest variable is accessed. If there is no such variable declared in this scope, the global variable is accessed.
Func test01(a float32) {FMT.Printf("a type = %T\n"); a) //a type = float32 } func main() { fmt.Printf("a type = %T\n", a) //a type = int, Printf("a type = %T\n", "a uint8 ", "a type = %T\n", "a type = %T\n", "a type = %T\n", "a type = %T\n", "a type = %T\n", "a type = %T\n", "a type = %T\n", a) //a type = float64 } fmt.Printf("a type = %T\n", A) //a type = uint8 test01(3.14) test02()} func test02() {mt.Printf("a type = %T\n", a) //a type = int}Copy the code