5、go的函数

函数写法

func main() {
	sum := cal(1, 1)
	fmt.Println(sum)	// 2
}
// 函数名首字母如果大小,可以在其他包中引用
// 函数语法:参数列表(可以0个或多个),返回值类型列表(可以0个或多个)
func cal(num1 int, num2 int) (int) {	// 如果只有一个返回值参数,可以不写小括号,直接int就好了
	return num1 + num2
}

如果没有返回值,对应的位置不写就行了,例如:

func main() {
	cal(1, 1)
}

func cal(num1 int, num2 int) {	// 没有返回值,这个位置可以不写
	fmt.Println(num1 + num2)	// 2
}

函数返回多个结果参数,例如:

func main() {
	sum, result := cal2(1, 1)
	fmt.Println(sum)    // 2
	fmt.Println(result) // 0
}

func cal2(num1 int, num2 int) (int, int) { // 返回两个参数,一个是两数之和,一个是两数之差
	return num1 + num2, num1 - num2
}

如果只取一个结果,例如;

func main() {
	// 如果返回的参数只想要其中一个,使用_ 把另一个给忽略了就行了
	sum, _ := cal2(1, 1)
	fmt.Println(sum)    // 2
}

func cal2(num1 int, num2 int) (int, int) { // 返回两个参数,一个是两数之和,一个是两数之差
	return num1 + num2, num1 - num2
}

问题:

我给两个值进行交换,结果发现交换失败

func main() {
	var num1 int = 10
	var num2 int = 20
	fmt.Printf("交换前两个数: num1: %v, num2: %v \n", num1, num2)	// 10, 20
	exchangeNum(num1, num2)
	fmt.Printf("交换后两个数: num1: %v, num2: %v \n", num1, num2)	// 10, 20
}

// 给两个参数互相交换值
func exchangeNum(num1 int, num2 int) {
	var t int
	t = num1
	num1 = num2
	num2 = t
}

内存分析:
image
所以基本数据类型和数组默认都是值传递,即值拷贝,在函数内修改,不会影响原来的值

重载问题

go不支持重载,如果有多个同名的函数,尽管参数不同,也会编译报错的

参数数量是可变的,例如:

func main() {
	test(3)
	test(1, 1, 1)
}

func test(args ...int) {
	// 函数内部处理可变参数时候,把可变参数当作切片处理
	for i := 0; i < len(args); i++ {
		fmt.Println(args[i])
	}
}

会打印一个3,然后打印3个1

值传递数据类型参数

func main() {
	var num int = 10
	fmt.Println(num) // 10
	test(&num)
	fmt.Println(num) // 30
}

func test(num *int) {
	// 指针修改函数传递值
	*num = 30
}

内存分析:
image

数据类型——函数

函数是数据类型,所以可以赋值给一个变量接收

func main() {
	// 函数也是一种数据类型, 可以赋值给一个变量
	a := test
	fmt.Printf("a的类型: %T, test的类型: %T   \n", a, test) // a的类型: func(int), test的类型: func(int)

	// 通过该变量可以给对应的函数调用赋值
	a(10)	// 10
}

func test(num int) {
	fmt.Println(num)
}

go里面把函数也当成数据类型,所以可以当作参数入参

func main() {
	// 调用test02函数
	test02(10, 3.14, test) // 最后一个参数传入test函数
	test02(10, 3.14, a)    // 传入a也可以, 是等价的
}

func test(num int) {
	fmt.Println(num)
}
func test02(num1 int, num2 float32, testFunc func(int)) {
	fmt.Println("------test02")
	testFunc(99)	// 这里又调用了test函数
}

为了简化数据类型定义,go支持自定义数据类型

	type myInt int
	var num myInt = 30
	fmt.Println("num: ", num) // 30

	var abc int = 10
	// 虽然num是myInt类型的,是int的别名,但是myInt和int不是一种数据类型,所以这样会报错
	//abc = num

	// 如果想要赋值给abc这个int的变量, 可以把myInt类型转为int类型
	abc = int(num)
	fmt.Println("abc: ", abc) // 30

既然go支持自定义数据类型,那函数也是数据类型,所以也可以给函数给别名

func test(num int) {
	fmt.Println(num)
}
// 给上面的test函数给别名
type myFunc func(int)

func test02(num1 int, num2 float32, testFunc myFunc) {	// 这里入参使用自函数别名
	fmt.Println("------test02")
	testFunc(99) // 这里又调用了test函数
}

有的还可以对函数的返回值命名
image

init函数

func main() {
	fmt.Println("main函数被执行!")
}
func init() {
	fmt.Println("init函数被执行!")	// 先被执行
}

函数的执行顺序:

var num int = t()	// 1、最先被执行,全部变量的定义

func t() int {
	fmt.Println("test行数被执行")
	return 10;
}

func main() {
	fmt.Println("main函数被执行!")	// 3、最后被执行
}
func init() {
	fmt.Println("init函数被执行!")	// 2、被执行
}

打印:
image

匿名函数

func main() {
	// 定义匿名函数: 定义的同时调用
	result := func(num1 int, num2 int) int {
		return num1 + num2
	}(10, 20)
	fmt.Println(result) // 30

	// 将匿名函数赋给一个变量,就是函数类型的变量
	sub := func(num1 int, num2 int) int {
		return num1 - num2
	}
	// 直接调用sub就等于调用匿名函数了
	result2 := sub(30, 70)
	fmt.Println(result2) // -40
}

闭包

// 求和操作
// 函数名是getSum,参数是空,
// getSum函数的返回值是一个函数,这个函数参数是int类型,返回值也是int类型
func getSum() func(int) int {
	var sum int = 0		// 这个变量的值是保留状态,反复使用的感觉
	return func(i int) int {	// 返回的匿名函数 + sum(也就是匿名函数以外的变量),组成的一个整体
		sum = sum + i
		return sum
	}
}
func main() {
	f := getSum()
	fmt.Println(f(1))	// 1
	fmt.Println(f(2))	// 3
	fmt.Println(f(3))	// 6
	fmt.Println(f(4))	// 10
}

defer

func main() {
	fmt.Println(add(30, 60))
}
func add(num1 int, num2 int) int {
	// 遇到defer关键字,不会立马执行defer后面的代码,
	// 会把defer后面的代码先压入栈,先执行下面的代码,defer后面的代码变量的值不会因为后面代码而改变
	defer fmt.Println("num1=", num1)
	defer fmt.Println("num2=", num2)

	var sum int = num1 + num2
	fmt.Println("sum=", sum)
	return sum
}

打印:
image

字符串函数

func main() {
	// 统计字符长度, len()
	str := "golang你好"     // 汉字是utf-8字符集,一个汉字是3个字节
	fmt.Println(len(str)) // 12

	// 对字符遍历:
	// 方式1: for-range
	for i, value := range str {
		fmt.Printf("索引为:%d, 具体的值为:%c   \n", i, value)
	}
	// 方式2: r:=[]rune(str)
	r := []rune(str)
	for i := 0; i < len(r); i++ {
		fmt.Printf("%c   \n", r[i])
	}

	// 字符串转整数
	num1, _ := strconv.Atoi("666")
	fmt.Println(num1)

	// 整数转字符串
	str1 := strconv.Itoa(88)
	fmt.Println(str1)

	// 统计一个字符串中有几个指定的字符
	count := strings.Count("golanggolandjava", "go") // 包含了2个"go"
	fmt.Println(count)                               // 2

	// 不区分大小写比较字符串
	flag := strings.EqualFold("hello", "HELLO")
	fmt.Println(flag) // true
	// 区分大小写比较字符串,使用==比较
	fmt.Println("hello" == "HELLO") // false

	// 返回指定字符在字符串出现的索引值,如果没有,返回-1
	index := strings.Index("golanggolandjava", "and")
	fmt.Println(index) // 9

	// 字符串替换,最后一个参数表示替换几个,如果是2,那就替换2个,如果传-1表示全部替换
	replaceStr := strings.Replace("gogogo", "go", "golang", 1)
	fmt.Println(replaceStr) // golanggogo

	// 根据某个字符分割标识,将字符串拆分成数组
	splitStr := strings.Split("go-python-java", "-")
	fmt.Println(splitStr) // [go python java]

	// 字符串字母进行大小写转行
	toLower := strings.ToLower("GO")
	fmt.Println(toLower) // go
	toUpper := strings.ToUpper("go")
	fmt.Println(toUpper) // GO

	// 去掉字符串两边空格
	trimSpaceStr := strings.TrimSpace("      go and java      ")
	fmt.Println(trimSpaceStr) // go and java

	// 去掉字符串左右两边指定的字符
	trimStr := strings.Trim("~go~", "~")
	fmt.Println(trimStr) // go

	// 去掉字符串左边指定的字符
	trimLeft := strings.TrimLeft("~go~", "~")
	fmt.Println(trimLeft) // go~
	// 去掉字符串右边指定的字符
	trimRight := strings.TrimRight("~go~", "~")
	fmt.Println(trimRight) // ~go

	// 判断字符串是否以指定字符开头
	hasPrefixStr := strings.HasPrefix("https://www.baidu.com/", "https")
	fmt.Println(hasPrefixStr) // true

	// 判断字符串是否以指定字符结尾
	hasSuffixStr := strings.HasSuffix("https://www.baidu.com/", "https")
	fmt.Println(hasSuffixStr) // false
}

日期时间函数

func main() {
	// 时间和日期函数:
	// 获取当前时间,调用time的Now()函数
	now := time.Now()
	// 返回一个结构体
	fmt.Println(now)                            // 2022-06-16 09:05:29.8604469 +0800 CST m=+0.003519401
	fmt.Printf("%v ~~~ 对应的类型是:%T \n", now, now) // 对应的类型是:time.Time

	// 调用结构体中的方法:
	fmt.Printf("年:%v \n", now.Year())
	fmt.Printf("月:%v \n", now.Month())
	fmt.Printf("日:%v \n", now.Day())
	fmt.Printf("时:%v \n", now.Hour())
	fmt.Printf("分:%v \n", now.Minute())
	fmt.Printf("秒:%v \n", now.Second())

	// 日期格式化
	format := now.Format("2006/01/02 15/04/05") // 这个时间时go语言开发时的时间
	fmt.Println(format)                         // 2022/06/16 09/17/41

	// 任意格式
	format2 := now.Format("01/02 15:04:05")
	fmt.Println(format2) // 06/16 09:19:29
}

内置函数

常用内置函数:

func main() {
	// len()函数,获取字符串长度
	str := "golang"
	fmt.Println(len(str)) // 6

	// new()函数,分配内存,主要用来分配值的类型,基本数据类型
	num := new(int)
	// num的类型:*int, 值:0xc00000a0c0, 地址:0xc000006030, 指针指向的值:0
	fmt.Printf("num的类型:%T, 值:%v, 地址:%v, 指针指向的值:%v", num, num, &num, *num)

	// make()函数,分配内存,主要用来分配引用类型,指针、切片、map、管道等
}
posted @ 2022-11-25 15:59  aBiu--  阅读(13)  评论(0编辑  收藏  举报