补充关于闭包,递归,匿名函数,回调函数,strings包、strconv包的使用。
闭包
go语言支持函数式编程:
支持将一个函数作为另一个函数的参数,也支持将一个函数作为另一个函数的返回值。
闭包(closure):
一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量(外层函数中的参数,或者外层函数中直接定义的变量),并且该外层函数的返回值就是这个内层函数。这个内层函数和外层函数的局部变量,统称为闭包结构。
局部变量的生命周期会发生改变,正常的局部变量随着函数调用而创建,随着函数的结束而销毁。
但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还要继续使用。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| package main
import "fmt"
func main() {
res1 := increment() fmt.Printf("%T\n", res1) fmt.Println(res1) v1 := res1() fmt.Println(v1) v2 := res1() fmt.Println(v2) fmt.Println(res1()) fmt.Println(res1()) fmt.Println(res1()) fmt.Println(res1())
res2 := increment() fmt.Println(res2) v3 := res2() fmt.Println(v3) fmt.Println(res2())
fmt.Println(res1()) }
func increment() func() int { i := 0 fun := func() int { i++ return i } return fun }
|
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12
| func() int 0xdbfd60 1 2 3 4 5 6 0xdbfd40 1 2 7
|
递归
递归函数(recursion):一个函数自己调用自己,就叫做递归函数。
一个函数自己调用自己,就叫做递归调用,一个递归函数一定要有出口,否则会陷入死循环。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package main
import "fmt"
func main() {
sum := getSum(5) fmt.Println(sum)
res := getFibonacci(12) fmt.Println(res) } func getFibonacci(n int) int { if n == 1 || n == 2 { return 1 } return getFibonacci(n-1) + getFibonacci(n-2) }
func getSum(n int) int { fmt.Println("**********") if n == 1 { return 1 } return getSum(n-1) + n }
|
运行结果:
1 2 3 4 5 6 7
| ********** ********** ********** ********** ********** 15 144
|
匿名函数
匿名:没有名字
匿名函数:没有名字的函数。
定义一个匿名函数,直接进行调用。通常只能使用一次。也可以使用匿名函数赋值给某个函数变量,那么就可以调用多次了。
匿名函数:
Go语言是支持函数式编程:
将匿名函数作为另一个函数的参数,回调函数
将匿名函数作为另一个函数的返回值,可以形成闭包结构。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package main
import "fmt"
func main() { fun1() fun1() fun2 := fun1 fun2()
func() { fmt.Println("我是一个匿名函数。。") }()
fun3 := func() { fmt.Println("我也是一个匿名函数。。") } fun3() fun3()
func(a, b int) { fmt.Println(a, b) }(1, 2)
res1 := func(a, b int) int { return a + b }(10, 20) fmt.Println(res1)
res2 := func(a, b int) int { return a + b } fmt.Println(res2)
fmt.Println(res2(100, 200)) }
func fun1() { fmt.Println("我是fun1()函数。。") }
|
输出结果:
1 2 3 4 5 6 7 8 9 10
| 我是fun1()函数。。 我是fun1()函数。。 我是fun1()函数。。 我是一个匿名函数。。 我也是一个匿名函数。。 我也是一个匿名函数。。 1 2 30 0x63e160 300
|
回调函数
高阶函数:
根据go语言的数据类型的特点,可以将一个函数作为另一个函数的参数。
fun1(),fun2()
将fun1函数作为了fun2这个函数的参数。
fun2函数:就叫高阶函数
接收了一个函数作为参数的函数,高阶函数
fun1函数:回调函数
作为另一个函数的参数的函数,叫做回调函数。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package main
import "fmt"
func main() { fmt.Printf("%T\n", add) fmt.Printf("%T\n", oper)
res1 := add(1, 2) fmt.Println(res1)
res2 := oper(10, 20, add) fmt.Println(res2)
res3 := oper(5, 2, sub) fmt.Println(res3)
fun1 := func(a, b int) int { return a * b }
res4 := oper(10, 4, fun1) fmt.Println(res4)
res5 := oper(100, 8, func(a, b int) int { if b == 0 { fmt.Println("除数不能为零") return 0 } return a / b }) fmt.Println(res5)
} func oper(a, b int, fun func(int, int) int) int { fmt.Println(a, b, fun) res := fun(a, b) return res }
func add(a, b int) int { return a + b }
func sub(a, b int) int { return a - b }
|
输出结果:
1 2 3 4 5 6 7 8 9 10 11
| func(int, int) int func(int, int, func(int, int) int) int 3 10 20 0xb8fc20 30 5 2 0xb8fc40 3 10 4 0xb8fc60 40 100 8 0xb8fc80 12
|
字符串
Go中的字符串是一个字节的切片。
可以通过将其内容封装在“”中来创建字符串。Go中的字符串是Unicode兼容的,并且是UTF-8编码的。
字符串是一些字节的集合。理解为一个字符的序列。
每个字符都有固定的位置(索引,下标,index:从0开始,到长度减1)
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package main
import "fmt"
func main() { s1 := "hello中国" s2 := `hello world` fmt.Println(s1) fmt.Println(s2)
fmt.Println(len(s1)) fmt.Println(len(s2))
fmt.Println(s2[0]) a := 'h' b := 104 fmt.Printf("%c,%c,%c\n", s2[0], a, b)
for i := 0; i < len(s2); i++ { fmt.Printf("%c\t", s2[i]) } fmt.Println()
for _, v := range s2 { fmt.Printf("%c", v) } fmt.Println()
slice1 := []byte{65, 66, 67, 68, 69} s3 := string(slice1) fmt.Println(s3)
s4 := "abcdef" slice2 := []byte(s4) fmt.Println(slice2)
fmt.Println(s4) }
|
输出结果:
1 2 3 4 5 6 7 8 9 10 11
| hello中国 hello world 11 11 104 h,h,h h e l l o w o r l d hello world ABCDE [97 98 99 100 101 102] abcdef
|
strings包
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| package main
import ( "fmt" "strings" )
func main() { s1 := "helloworld" fmt.Println(strings.Contains(s1, "abc")) fmt.Println(strings.ContainsAny(s1, "abcd")) fmt.Println(strings.Count(s1, "lloo"))
s2 := "20230525课堂笔记.txt" if strings.HasPrefix(s2, "202305") { fmt.Println("23年5月的文件。。") } if strings.HasSuffix(s2, ".txt") { fmt.Println("文本文档。。") }
fmt.Println(strings.Index(s1, "lloo")) fmt.Println(strings.IndexAny(s1, "abcdh")) fmt.Println(strings.LastIndex(s1, "l"))
ss1 := []string{"abc", "world", "hello", "ruby"} s3 := strings.Join(ss1, "-") fmt.Println(s3)
s4 := "123,4563,aaa,49595,45" ss2 := strings.Split(s4, ",") for i := 0; i < len(ss2); i++ { fmt.Println(ss2[i]) }
s5 := strings.Repeat("hello", 5) fmt.Println(s5)
s6 := strings.Replace(s1, "l", "*", -1) fmt.Println(s6)
s7 := "heLLo WOrlD**123.." fmt.Println(strings.ToLower(s7)) fmt.Println(strings.ToUpper(s7))
fmt.Println(s1) s8 := s1[:5] fmt.Println(s8) fmt.Println(s1[5:]) }
|
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| false true 0 23年5月的文件。。 文本文档。。 -1 0 8 abc-world-hello-ruby 123 4563 aaa 49595 45 hellohellohellohellohello he**owor*d hello world**123.. HELLO WORLD**123.. helloworld hello world
|
strconv包
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| package main
import ( "fmt" "strconv" )
func main() { s1 := "true" b1, err := strconv.ParseBool(s1) if err != nil { fmt.Println(err) return } fmt.Printf("%T,%t\n", b1, b1)
ss1 := strconv.FormatBool(b1) fmt.Printf("%T,%s\n", ss1, ss1)
s2 := "100" i2, err := strconv.ParseInt(s2, 2, 64) if err != nil { fmt.Println(err) return } fmt.Printf("%T,%d\n", i2, i2)
ss2 := strconv.FormatInt(i2, 10) fmt.Printf("%T,%s\n", ss2, ss2)
i3, err := strconv.Atoi("-42") fmt.Printf("%T,%d\n", i3, i3) ss3 := strconv.Itoa(-42) fmt.Printf("%T,%s\n", ss3, ss3) }
|
输出结果:
1 2 3 4 5 6
| bool,true string,true int64,4 string,4 int,-42 string,-42
|
“strconv”用于进行字符串和基本类型之间的转换。在main函数中,首先演示了布尔类型的转换。使用strconv.ParseBool函数将s1转换为bool类型的变量b1。如果转换过程中出现错误,则会打印错误信息并返回。否则,使用fmt.Printf函数输出b1的类型和值。接下来,使用strconv.FormatBool函数将b1转换为字符串类型的变量ss1,演示了整数类型的转换,使用strconv.ParseInt函数将s2按照二进制解析为int64类型的变量i2。使用strconv.FormatInt函数将i2按照十进制转换为字符串类型的变量ss2,使用strconv.Atoi函数将字符串”-42”转换为int类型的变量i3,使用strconv.Itoa函数将整数-42转换为字符串类型的变量ss3。