0
点赞
收藏
分享

微信扫一扫

《网关微服务技术架构:构建高效可扩展的服务网关》

年夜雪 2024-05-30 阅读 19

目录

初识函数

引入包

init函数

匿名函数

闭包

defer关键字

系统函数

错误处理


初识函数

为完成某一功能的程序指令(语句)的集合称为函数,函数的作用就是提高代码的复用性和可维护性,减少代码的冗余。接下来我们举一个简单的例子,看一看函数如何进行处理和调用:

package main
import "fmt"
/*	函数基本格式
	func 函数名(参数列表) (返回值列表) {
		函数体
		return 返回值列表
	}
*/
// 求和函数
func cal(a, b int) int {
	return a + b
}
func main() {
	sum := cal(1, 2)
	fmt.Println(sum) // 3
}

函数有一些区别于其他语言的一些细节所在,接下来本文将对这些细节及其所起作用一一讲解:

package main
import "fmt"
// 求和函数
func cal(a, b int) (int, int) {
	result1 := a + b
	result2 := a - b
	return result1, result2
}
func main() {
	sum1, sum2 := cal(1, 2)
	// 如果不想接收第二个值,可以使用下划线占位进行忽略
	//sum1, _ := cal(1, 2)
	fmt.Println(sum1, sum2) // 3  -1
}
// Go语言中不支持函数重载,但可以使用不同的函数名  
func printInt(x int) {  
    fmt.Println("Printing an integer:", x)  
}  
func printFloat(x float64) {  
    fmt.Println("Printing a float:", x)  
}  

func main() {  
    printInt(10)      // 调用printInt  
    printFloat(10.5)  // 调用printFloat  
} 
package main
import "fmt"
// 定义一个函数,函数参数为:可变参数 ... 参数的数量可变
// args...int 可以传入任意多个数量的int类型的数据,传入0个,1个...n个
func test(args ...int) {
	// 函数内部处理可变参数的时候,可将可变参数当作切片来处理
	// 遍历可变参数
	for i := 1; i < len(args); i++ {
		fmt.Println(i, args[i])
	}
}

func main() {
	test(1, 2) // 1 2
	fmt.Println("-----------")
	test() // 空
}
package main
import "fmt"
func test(num int) {
	num = 30
	fmt.Println(num)
}

func main() {
	var num int = 10
	test(num) // 30
	fmt.Println(num) // 10
}
package main
import "fmt"
func test(num *int) {
	*num = 30
	fmt.Println(num)
}

func main() {
	var num int = 10
	fmt.Println(&num) // 0xc00000a0c8
	test(&num)        // 调用test函数,将num的地址作为参数传递给test函数,test函数中修改num的值,结果为0xc00000a0c8
	fmt.Println(num)  // 30
}
package main
import "fmt"
// 定义函数
func test(num int) {
	fmt.Println(num)
}

func main() {
	// 函数也是一种数据类型,可以赋值给变量
	a := test
	fmt.Printf("a的类型是: %T, test函数的类型是:%T \n", a, test) // a的类型是: func(int), test函数的类型是:func(int)
	// 通过赋值变量,调用函数
	a(10) // 10
}
package main
import "fmt"
// 定义函数
func test(num int) {
	fmt.Println(num)
}
// 定义函数,把函数作为参数传递给另一个函数
func test2(num int, testfunc func(int)) {
	fmt.Println("---")
	testfunc(num)
}

func main() {
	// 函数也是一种数据类型,可以赋值给变量
	a := test
	fmt.Printf("a的类型是: %T, test函数的类型是:%T \n", a, test) // a的类型是: func(int), test函数的类型是:func(int)
	// 通过赋值变量,调用函数
	a(10) // 10
	// 函数作为参数传递给另一个函数
	test2(10, test) // --- 10
}
// 自定义数据类型(相当于起别名):给int类型起了别名叫myInt类型
type myInt int
var num1 myInt = 10
fmt.Println(num1) // 10

//var num2 int = 10
//num2 = num1 // 虽然是别名,但是在go语言中,别名是不能进行隐式转换的,还是认为myInt与int类型不同
package main
import "fmt"
// 定义函数
func test(num int) {
	fmt.Println(num)
}
// 定义函数,把函数作为参数传递给另一个函数
// 自定义数据类型
type myfunc func(int)
func test2(num int, testfunc myfunc) {
	fmt.Println("---")
	testfunc(num)
}

func main() {
	// 函数也是一种数据类型,可以赋值给变量
	a := test
	fmt.Printf("a的类型是: %T, test函数的类型是:%T \n", a, test) // a的类型是: func(int), test函数的类型是:func(int)
	// 通过赋值变量,调用函数
	a(10) // 10
	// 函数作为参数传递给另一个函数
	test2(10, test) // --- 10
}

当然这里还支持函数返回值命名,里面顺序无所谓,具体如下代码示例:

package main
import "fmt"
func test(num1 int, num2 int) (sum int, sub int) {
	sum = num1 + num2
	sub = num1 - num2
	return
}

func main() {
	sum, sub := test(10, 2)
	fmt.Println(sum, sub) // 12 8
}

引入包

在Go语言中,包(package)是一个非常重要的概念,它用于组织和管理代码。

以下是导包后调用的基础案例:

我们在导包的时候,也是需要关注一些细节方面的内容,方便我们快速导包使用,细节如下:

当然也可以给包起别名,起完别名之后原来的包名就不能再使用了:

init函数

初始化函数,可以用来进行一些初始化的操作每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用。示例代码如下所示:

匿名函数

go语言支持匿名函数,如果我们某个函数只是希望使用一次,可以考虑使用匿名函数,以下是使用匿名函数的使用方式:

package main
import "fmt"
func main() {
	// 定义匿名函数
	result := func(num1 int, num2 int) int {
		return num1 + num2
	}(10, 3)
	fmt.Println(result) // 13
}
package main
import "fmt"
func main() {
	// 将匿名函数赋值给变量,然后通过变量调用匿名函数
	sub := func(a, b int) int {
		return a - b
	}
	// 调用匿名函数
	result := sub(10, 5)
	fmt.Println(result) // 5
}
package main
import "fmt"
// 设置全局匿名函数
var sub = func(a, b int) int {
	return a - b
}

func main() {
	// 调用匿名函数
	result := sub(10, 5)
	fmt.Println(result) // 5
}

闭包

闭包就是一个函数和与其相关的引|用环境组合的一个整体。

package main
import "fmt"
// 函数求和,函数的名字是getSum,参数为空
// getSum返回一个函数,这个函数是int类型的参数,返回值也是int类型
func getSum() func(int) int {
	var sum int = 0
	return func(num int) int {
		sum += num
		return sum
	}
}

func main() {
	f := getSum()
    // 可以看到匿名函数中引用的那边变量会一直保存再内存中,可以一直使用
	fmt.Println(f(1)) // 1
	fmt.Println(f(2)) // 3
	fmt.Println(f(3)) // 6
}

defer关键字

在函数中,程序员经常需要创建资源,为了在函数执行完毕后,及时的释放资源,Go的设计者提供defer关键字,接下来通过如下代码进行讲解:

package main
import "fmt"
func add(num1, num2 int) int {
	// 在go中,程序遇到defer关键字,不会立即执行defer后面的语句,而是将defer后面的语句放入到栈中,然后执行函数后面的语句。
	defer fmt.Println("num1 = ", num1)
	defer fmt.Println("num2 = ", num2)
	// 栈的特点是先进后出,所以defer后面的语句会先执行
	// 在函数执行完毕后,从栈中取出语句开始执行,按照先进后出的顺序执行
	sum := num1 + num2
	fmt.Println("sum = ", sum)
	return sum
}
func main() {
	fmt.Println(add(1, 2))
}

最终得到的结果如下所示:

系统函数

系统函数是一个相对模糊的概念,它可以指代任何与底层系统交互或执行特定系统级别任务的函数。在Go语言中,这些函数可能来自标准库、第三方库、通过系统调用实现的功能或者内置的函数,接下来我们就讲解一下go语言中常见的内置函数,使用内置函数也不用导包的,直接用就行:

func main() {
	// 统计字符串的长度,按字节进行统计
	str := "hello world"
	fmt.Println(len(str)) // 11
}
func main() {
	str := "hello world"
	// 对字符串进行变量
	// 方式1:利用键值循环:for - range
	for i, value := range str {
		fmt.Printf("索引为:%d, 具体的值为:%c \n", i, value)
	}
	fmt.Println("---------------------------------")
	// 方式2:利用 r:=[]rune(str)
	r := []rune(str)
	for i := 0; i < len(r); i++ {
		fmt.Printf("索引为:%d, 具体的值为:%c \n", i, r[i])
	}
}

最终得到的结果如下所示:

func main() {
	// 字符串转整数
	num1, _ := strconv.Atoi("123")
	fmt.Println(num1) // 123
	// 整数转字符串
	num2 := strconv.Itoa(123)
	fmt.Println(num2) // "123"
}
func main() {
	// 查找子串是否在指定的字符串中
	result := strings.Contains("javaandgolang", "go")
	fmt.Println(result) // true
}
func main() {
	// 查找子串是否在指定的字符串中
	result := strings.Count("javaandgolang", "a")
	fmt.Println(result) // 4
}
func main() {
	fmt.Println(strings.EqualFold("go", "Go")) // true
}
func main() {
	result := strings.Index("javaandgolang", "a")
	fmt.Println(result) // 1
}

当然下面还有一些函数,这里就不再一一演示了:

当然go语言还内置了时间函数,这里进行一个简单的演示:

package main
import (
	"fmt"
	"time"
)
func main() {
	// 日期时间函数
	now := time.Now()
	// Now() 是一个结构体,类型是time.Time, 返回的是当前时间
	// 2024-05-26 16:05:18.4238005 +0800 CST m=+0.000660501 ~~~ 对应的类型为: time.Time
	fmt.Printf("%v ~~~ 对应的类型为: %T\n", now, now)

	// 获取年月日
	fmt.Printf("年: %d\n", now.Year())  // 2024
	fmt.Printf("月: %d\n", now.Month()) // 5
	fmt.Printf("日: %d\n", now.Day())   // 26

	// 获取当前年月日时分秒的字符串 Format()函数是结构体的方法,作用是格式化时间
	fmt.Printf("年月日时分秒: %s\n", now.Format("2006-01-02 15:04:05")) // 2024-05-26 16:05:18
}

最终达到的效果如下所示:

错误处理

当函数出现运行错误的时候,会导致程序被中断,是无法继续执行后续代码的,所以我们需要对错误进行一个处理,以下是程序出现错误时的情况:

package main
import "fmt"
func test() {
	// 利用defer+recover机制,捕获异常,defer后加上匿名函数的调用
	defer func() {
		// 调用recover()函数,捕获异常
		err := recover()
		if err != nil {
			// 捕获异常后,执行相应的处理逻辑
			fmt.Println("错误已经捕获")
			fmt.Println("捕获异常:", err)
		}
	}()
	num1 := 10
	num2 := 0
	result := num1 / num2
	fmt.Println(result)
}

func main() {
	test()
	fmt.Println("上述逻辑正常,开始执行下面的代码~")
	fmt.Println("main函数执行完毕")
}

最终实现的效果如下所示:

如果想自定义错误的话,可以采用下面的方式进行:

package main
import (
	"errors"
	"fmt"
)
func test() (err error) {
	num1 := 10
	num2 := 0
	// 自定义错误
	if num2 == 0 {
		// 抛出自定义错误
		return errors.New("除数不能为0")
	} else {
		result := num1 / num2
		fmt.Println(result)
		// 如果没有错误,返回零值
		return nil
	}
}

func main() {
	err := test()
	if err != nil {
		fmt.Println("自定义错误", err)
	}
	fmt.Println("上述逻辑正常,开始执行下面的代码~")
	fmt.Println("main函数执行完毕")
}

最终实现的结果如下所示:

有一种情况:程序出现错误以后,后续代码就没有必要执行,想让程序中断,退出程序:借助:builtin包下内置函数:panic

举报

相关推荐

0 条评论