GO learning function (Function)

GO series

1. Hello World of GO Learning
2. Introductory Grammar of GO Learning
3. Slicing Operation of GO Learning
4. Map Operation of GO Learning
5. Structure Operation of GO Learning
6. Channel of GO Learning (Channel)
7. GO Learning of Multithreading (goroutine)
8. GO learning function (Function)
9. GO learning interface (Interface)

foreword

According to the company's current tasks, go learning is the only way to go. Although the industry is difficult, but the skills are not overwhelming, we still work hard! ! ! The method was mentioned in the chapter on the structure
before . The method is actually similar to the function, but the difference between the method and the function is that the function does not belong to any type, and the method belongs to a specific type . This sentence is also mentioned in the structure. , but there are many details that need to be paid attention to in the use of functions, and this article will give detailed explanations.

1. What is a function?

  • In the Go language, a function (Function) is an executable code block ( extracting a specific function to form a code fragment ) for performing a specific task or operation.
  • Functions are the basic components in the Go language, which realizes the mechanism of modularization and reuse, making the code more structured and maintainable.

Here is a list of the features I can find and think of (not limited to these):

Features of functions in Go language:

  • No need to declare prototype
  • Support variable parameters
  • Support multiple return values
  • Support for named return parameters
  • Support for anonymous functions and closures
  • Function is also a type, you can assign a function to a variable
  • Functions cannot be nested
  • Functions cannot be overloaded like in JAVA

2. Function declaration

  • Function declarations use the keywordfunc
  • Basic syntax:func 函数名(参数列表) 返回值列表 { 函数体 }
  • Naming conventions for function names: 1. It is best to name with camel case, see the name, for example: ; addNum(a,b int){}2. The first letter cannot be a number; 3. The first letter can be used by this package and other package files, similar to public, for example: AddNum(a,b int){}, Lowercase initials are similar to private, for example:addNum(a,b int){}
  • The parameter list is separated by commas, each parameter consists of parameter name and type, for example:func list(pageNo int, pageSize int) (int, error) { }
  • If multiple parameters are of the same type, the previous parameter type can be omitted, for example:func list(pageNo, pageSize int) (int, error) { }
  • Use ...the syntax to define variable parameters for the function, and the running function accepts a variable number of parameters, such as: ``
  • It can be omitted if there is no return value, for example:func save(id int, name string) { }
  • Parentheses are not required (or available) if it is a return value, for example:func save(id int, name string) int { }
  • If there are multiple return values, wrap them in parentheses and correspond to the return statement one by one, for example:func save(id int, name string) (int, string) { ...return 1,'success' }
  • As mentioned above, named return functions are supported, such as:func divideAndRemainder(a, b int) (quotient, remainder int) { }
  • Use keywords functo define functions, curly braces cannot start a new line

Above code:

3. Function call

  • When accepting function return values, if multiple return values ​​are accepted one by one, for example:count, result := save(1, "张三")
  • If you only need to accept one of the return values ​​and the other does not, you can use an underscore _to ignore it, for example:count, _ := save(1, "张三")
  • If the main package wants to call functions in other packages, the functions in other packages need to be defined as accessible outside the package, and the first letter of the function name is capitalized. For example, when defining a func1 package: , you need to pay attention to the package name at this time func SumNum(a, b int) int { }, Must use the package name to call, for example:s := func1.SumNum(1, 2)

The following examples are examples of function definitions commonly used in the Go language for reference.
The examples are my brother and I typed one by one, the test passed, and the running results are attached, but it is still a bit complicated to see with the eyes, it is better to type it yourself, but it doesn’t matter to the big guys, and it doesn’t matter to the little ones like me. For white, you can only type it step by step to solve various errors before you can grow!

The package path is like this:
function package path

package func1

import "fmt"

// 定义无参数无返回值函数
func test() {
    
    
	fmt.Println("call test函数")
}

// 定义有参数无返回值函数,此函数私有的,只有内部可调
func addNum(a, b int) {
    
    
	c := a + b
	fmt.Printf("a + b = c %+v\n", c)
}

// 定义有参数有一个返回值函数, 次函数共有的,内部、外部包均可调
func SumNum(a, b int) int {
    
    
	c := a + b
	return c
}

// 定义可变参数函数
func ParamsFunc(params ...string) {
    
    
	for index, item := range params {
    
    
		fmt.Printf("可变参数为 %d:%+v\n", index, item)
	}
}

// 定义有参数有多个返回值函数
func List(pageNo, pageSize int) (int, []string) {
    
    
	fmt.Printf("查询操作...%d, %d", pageNo, pageSize)
	result := []string{
    
    "特斯拉", "广汽", "丰田", "宝马", "奥迪"}
	return 5, result
}

// 定义命名返回函数
func divideAndRemainder(a, b int) (quotient, remainder int) {
    
    
	quotient = a / b
	remainder = a % b
	return // 省略了 return 语句,并且直接返回了命名的返回值变量
}

The following example is a call to the function defined above.
Mainly, the path to import other packages is gotest.com/test/src/functionTest/func1

package main

import (
	"fmt"

	"gotest.com/test/src/functionTest/func1"
)

func main() {
    
    
	// 调用本包中的 save 函数,接受两个返回值
	count1, result := save(1, "张三")
	fmt.Printf("接受 save 函数的两个返回值 count1:%+v, result: %v\n", count1, result)

	// 调用本包中的 save 函数,接受一个返回值
	count, _ := save(1, "张三")
	fmt.Printf("接受 save 函数的一个返回值 count: %+v\n", count)

	// 调用无返回值函数
	list2(1, 10)

	// 调用 func1 包中的 SumNum 函数
	s := func1.SumNum(1, 2)
	fmt.Printf("调用 func1 包中的 SunNum 函数结果:%+v\n", s)
	
		// 调用可变参数函数
	func1.ParamsFunc("特斯拉", "广汽", "丰田", "宝马", "奥迪")

	// 调用 func1 包中的 List 函数
	totalCount, carBrands := func1.List(1, 10)
	fmt.Printf("调用 func1 包中的 List 函数,查询结果:%+v 条,数据:%v\n", totalCount, carBrands)
}

// 定义有参数有多个返回值函数
func save(id int, name string) (int, string) {
    
    
	fmt.Printf("保存%+v,%v\n", id, name)
	return 1, "success"
}

// 定义有多个参数无返回值函数
func list2(pageNo, pageSize int) {
    
    
	fmt.Println("list 接口")
}

operation result:

PS D:\workspaceGo\src\functionTest\main> go run funcTest.go
保存1,张三
接受 save 函数的两个返回值 count1:1, result: success
保存1,张三
接受 save 函数的一个返回值 count: 1
list 接口
调用 func1 包中的 SunNum 函数结果:3
可变参数为 0:特斯拉
可变参数为 1:广汽
可变参数为 2:丰田
可变参数为 3:宝马
可变参数为 4:奥迪
查询操作...1, 10调用 func1 包中的 List 函数,查询结果:5 条,数据:[特斯拉 广汽 丰田 宝马 奥迪]

4. Anonymous functions

  • In the Go language, anonymous functions are supported, that is, functions without function names
  • Anonymous functions can be assigned to variables
  • You can also call the anonymous function directly, which is a closure
package main

import "fmt"

func main() {
    
    
	// 定义匿名函数直接调用
	func() {
    
    
		fmt.Println("匿名函数调用!")
	}()
	// 定义匿名函数赋值给变量 hello
	hello := func() {
    
    
		fmt.Println("Hello 函数调用!")
	}
	// 调用匿名函数
	hello()
	// 定义有参数的匿名函数
	sum := func(a, b int) int {
    
    
		return a + b
	}
	fmt.Printf("加法计算:%+v\n", sum(1, 2))
}

operation result:

PS D:\workspaceGo\src\functionTest\main> go run .\anonymousFunc.go
匿名函数调用!
Hello 函数调用!
加法计算:3

Here's a slightly more complicated example:

In the following example, we store the function as a member in the array fns, the structure s, and the pipeline fc, and get the function to call.

package main

func main() {
    
    
	// 定义数据,元素类型是一个函数
	fns := [](func(a int) int){
    
    func(a int) int {
    
     return a + 1 }, func(a int) int {
    
     return a + 2 }}
	// 获取数组中的第一个函数调用,传参 10
	for _, fn := range fns {
    
    
		println(fn(10))
	}

	// 定义一个结构体,成员是一个 函数,调用结构体的 函数成员
	s := struct {
    
    
		fn func() string
	}{
    
    
		fn: func() string {
    
     return "Hello World!" },
	}
	println(s.fn())

	// 定义一个管道,发送一个函数,再接受到函数进行调用
	fc := make(chan func() string, 2)
	fc <- func() string {
    
     return "fc: Hello World!" }
	println((<-fc)())
}

operation result:

PS D:\workspaceGo\src\functionTest\main> go run .\anomymousFunc2.go
11
12
Hello World!
fc: Hello World!

5. Function parameters and return values

  • In Go, a function can be passed as an argument or as the return value of another function

The following is a relatively simple example, which accepts a function type parameter fc and returns an anonymous function.

package func1

import "fmt"

func CallFunc(fc func()) func() {
    
    
	fmt.Println("接受到函数 fc, 开始回调!")
	// 返回一个匿名函数
	return func() {
    
    
		fc()
		fmt.Println("call back...")
	}
}

Call code:

package main

import (
	"fmt"

	"gotest.com/test/src/functionTest/func1"
)

func main() {
    
    
fc := func() {
    
    
		fmt.Println("我是参数 fc 执行!")
	}
	fr := func1.CallFunc(fc)
	fr()
}

operation result:

PS D:\workspaceGo\src\functionTest\main> go run .\funcTest.go
接受到函数 fc, 开始回调!
我是参数 fc 执行!
call back...

The following is a classic case given by ChatGPT , which is convenient for a deeper understanding of how functions are used as parameters and return values ​​in actual scenarios. The example I have tested is ojbk.

  • Functions are used as parameters:
package main

import "fmt"

// 函数类型作为参数
type MathFunc func(int, int) int

// 加法函数
func add(a, b int) int {
    
    
	return a + b
}

// 减法函数
func subtract(a, b int) int {
    
    
	return a - b
}

// 计算函数,接收一个函数类型参数,并执行该函数
func calculate(a, b int, op MathFunc) int {
    
    
	return op(a, b)
}

func main() {
    
    
	// 调用 calculate 函数,传入 add 函数作为参数
	result := calculate(10, 5, add)
	fmt.Println("加法结果:", result)

	// 调用 calculate 函数,传入 subtract 函数作为参数
	result = calculate(10, 5, subtract)
	fmt.Println("减法结果:", result)
}

operation result:

PS D:\workspaceGo\src\functionTest\main> go run .\gptFunc.go
加法结果: 15
减法结果: 5
  • Functions used as return values:
package main

import "fmt"

// 返回一个加法函数
func getAddFunc() func(int, int) int {
    
    
	// 返回一个匿名函数,来实现计算
	return func(a, b int) int {
    
    
		return a + b
	}
}

// 返回一个减法函数
func getSubtractFunc() func(int, int) int {
    
    
	return func(a, b int) int {
    
    
		return a - b
	}
}

func main() {
    
    
	// 获取加法函数并调用
	addFunc := getAddFunc()
	result := addFunc(10, 5)
	fmt.Println("加法结果:", result)

	// 获取减法函数并调用
	subtractFunc := getSubtractFunc()
	result = subtractFunc(10, 5)
	fmt.Println("减法结果:", result)
}

Results of the:

PS D:\workspaceGo\src\functionTest\main> go run .\gptFunc2.go
加法结果: 15
减法结果: 5

6. Delay execution function

Features of defer:

  • Keyword defer user registration delay call, for example:defer println(i)
  • The registered deferred call will not be executed until return, so it is very suitable for closing, resource recovery and other operations
  • The defer statement is executed in a first-in, last-out manner
  • The variables in the defer statement are determined in the defer statement

Applicable scenarios for defer:

  • close stream operation
  • resource release
  • database connection release
  • wait…

6.1 defer first in last out

package main

func main() {
    
    
	arr := [5]int{
    
    1, 2, 3, 4, 5}
	for i := range arr {
    
    
		defer println(i)
	}
}

operation result:

PS D:\workspaceGo\src\functionTest\main> go run .\deferTest.go
4
3
2
1
0

It can be seen from the results that the defer that is looped first will not be executed until later.

6.2 defer closure function

package main

func main() {
    
    
	arr := [5]int{
    
    1, 2, 3, 4, 5}
	for i := range arr {
    
    
		defer func() {
    
    
			println(i)
		}()
	}
}

operation result:

PS D:\workspaceGo\src\functionTest\main> go run .\deferTest.go
4
4
4
4
4

Why are they all changed to 4? Because the loop body is a closure function, it will be executed immediately after declaration, but the i variable has been changed to 4 when the function is declared, so all four anonymous functions output 4.

Since defer seems to have many cases, please move here!

7. Error handling

  • Most functions in the Go language will return an error erroras an additional return value, the user indicates whether the function was executed successfully
  • Calling functions often need to check for errors so they can be handled as appropriate
  • For functions that do not return a value, you can use the error type to indicate whether the function is executed successfully, or to panictrigger an exception

7.1 Using error as a return parameter

In the example, we use the error type error to indicate whether the function is executed successfully, and return error if the function fails.

package main

import (
	"errors"
	"fmt"
)

func main() {
    
    
	err := divide(10, 0)
	if err != nil {
    
    
		fmt.Println("发生异常:", err)
	}
}

func divide(a, b int) error {
    
    
	if b == 0 {
    
    
		return errors.New("参数不能为 0")
	}
	return nil
}

operation result:

PS D:\workspaceGo\src\functionTest\main> go run .\errorFunc.go
发生异常: 参数不能为 0

7.2 Use panic to trigger exceptions

In the example, panic is used to trigger an exception to indicate the execution status of the function. When an error occurs in the function, the exception is directly triggered and the program execution is interrupted.
**Note:** We use the recover() function to catch and handle exceptions to avoid program crashes. recoverFunctions are only deferavailable in blocks, so use defer in the main() function to catch exceptions.

package main

func main() {
    
    
	defer func() {
    
    
		if r := recover(); r != nil {
    
    
			println("发生异常:", r)
		}
	}()
	divide2(10, 0)
}

func divide2(a, b int) {
    
    
	if b == 0 {
    
    
		panic("参数不能为 0")
	}
}

operation result:

PS D:\workspaceGo\src\functionTest\main> go run .\panicFunc.go
发生异常: (0xff1920,0x1011638)

8. Summary

Functions are a very important part of the Go language, they provide the ability of modularization, code reuse and abstraction. Through functions, we can divide complex logic into multiple small modules, making the code clearer, more readable, and easier to maintain and expand. The flexibility and variety of functions allow Go language to be used to solve various problems and scenarios.

At this stage, I am still in the learning stage of the Go language. There must be some places that are not considered comprehensively. All the examples in this article are written by hand and executed.
If you have any questions, please advise.
Let me know in the comments! ! ! Learn together and progress together! ! !

Guess you like

Origin blog.csdn.net/qq_19283249/article/details/132116497
Recommended