前言
Go中对函数的使用非常普遍,Go语言中没有默认参数这个概念。
函数格式
func 函数名(参数1,参数2,......)(返回值1,返回值2,....){ }
package main
import (
"fmt"
)
//函数
//函数的定义:Go是强类型语言必须给 参数、和返回值指定数据类型
//返回值使用和参数各使用()分开
func sum(x1 int, x2 int) (ret int) {
return x1 + x2
}
//没有返回值的函数
func f1(x1 int, x2 int) {
println(x1 + x2)
}
//没有参数的函数,也没有返回值的函数
func f3() {
fmt.Println("hello world")
}
//没有参数,但是有返回值的函数
func f4() string {
return "Hello World"
}
//函数的返回值可以命名也不可不命名
func f5(x int, y int) (ret int) {
ret = x + y
return //使用命名返回值,为ret,return后面可省略
}
//返回多个返回值
func f6() (int, string) {
return 1, "2"
}
//参数的类型简写:当函数有多个参数并且类型一致时,我们可以简写前面的参数类型
func f7(x, y, z int, n, o string, i, j bool) int {
return x + y
}
//可变长的参数:可变长参数必须放在最后
func f8(x string,y...int){
fmt.Println(x)
fmt.Println(y) //切片类型[1 2 3]
}
func main() {
ret := sum(1, 1)
fmt.Println(ret)
f1(2, 3)
str01 := f4()
fmt.Println(str01)
n, s := f6()
fmt.Println(n, s)
f8("下雨了",1,2,3)
}
函数参数
在Go语言中函数参数 通过 值类型传递!也就是说Go函数中的参数都是副本!
package main
import "fmt"
var s1 []string
func modify(s1 []string) {
s1[0] = "Zero" //修改了s1副本和s1本身对应的底层数组的同1个位置
}
func expansion(s2 []string) {
s2 = append(s2, "3")//扩展了、不算修改底层数组原处!
fmt.Println("我append数据了啊:",s2)
}
func main() {
s1 = []string{"1", "2"}
s1[0] = "一"
fmt.Println(s1)
modify(s1)
fmt.Println(s1)
expansion(s1)
fmt.Println("增加了没有",s1)
}
可变参数
可变长的参数
package main
import "fmt"
func f1(args ...interface{}) {
//args空接口类型的slice类型
fmt.Printf("类型:%T,可变参数值:%v
", args, args)
}
func main() {
f1()
f1(1)
f1(2, 3, 4)
//拆开传值
slice1 := []interface{}{5, 6, 7}
f1(slice1...)
}
闭包函数
1个函数嵌套了另1个函数,内层的函数引用了外层函数的参数或者变量之后,这个外层函数就行包一样包住了内层的函数,外层函数就叫闭包函数。
值得注意得是在Go的函数里面,你只能定义1个匿名函数,不能像Python 一样在函数内部在声明1个有名函数。
Python versus Golang 
闭包的原理
1.函数A可以作为函数B的1个参数传到函数B。
2.函数查找变量的顺序为 首先在自己内部找,找不到再去外层函数找。
3.函数A也可以作为函数B的返回值返回。
package main
import "fmt"
//1个简单的闭包函数 结束1个 int参数x,返回1个参数为int和返回值为int的函数
func adder(x int) func(int) int {
//内部的匿名函数引用了外部adder函数的变量x就称为闭包
return func(y int) int {
x += y
return x
}
}
func main() {
ret := adder(10)
fmt.Println(ret(100))
}
package main
import "fmt"
//1.需求在不改变CEO和CTO写得代码的情况下,把CTO写得的函数传到CEO函数中执行
//CEO写得函数(代码不能动)
func ceo(f func()) {
fmt.Println("This is CEO 函数")
f()
}
//CTO写的函数
func cto(y...int) {
var sum int
for _,v:=range(y){
sum+=v
}
fmt.Println("This is CTO 函数",sum)
}
//我写得函数
func wraper(f func(...int), a ...int) func() {
tmp := func() {
f(a...)
}
fmt.Println("This is function code by me")
return tmp
}
func main() {
// //匿名函数
// var f1 = func(x, y int) {
// fmt.Println(x + y)
// }
// f1(10, 20)
// //立即执行函数
// func(x, y int) {
// fmt.Println(x + y)
// }(10, 200)
//闭包
w := wraper(cto, 2020, 4,4,10,41)
ceo(w)
}
闭包面试题
package main
import "fmt"
func cal(base int) (func(int) int, func(int) int) {
add := func(i int) int {
base += i
return base
}
sub := func(i int) int {
base -= i
return base
}
return add, sub
}
func main() {
f1, f2 := cal(10)
//由于 内部函数一直引用外部函数的变量i,所以外部函数的变量i一直在变。
fmt.Println(f1(1), f2(2)) //11 9
fmt.Println(f1(3), f2(4)) //12 8
fmt.Println(f1(5), f2(6)) //13 7
}
递归函数
递归。递 、 归 所说的就是 递和归2个不同动作过程。有递也有归才叫递归。递就是压栈的过程,归就是出栈的过程。
递归函数就是自己调用自己
应用场景:问题相同但是每次问题规模都减小
必须有1个退出条件:递 、归 。递 、归不能无限得传递(压栈)达到了1临界值(达到了目的) 就得归(出栈)。

package main
import "fmt"
func test(n int){
fmt.Println("--->n=",n)
if n<3{
n++
test(n)//从这里进去的,就从这里出来
}
fmt.Println("<----n=",n)
}
func main() {
test(1)
}
/*
main函数开始执行
test(1):栈(一)
1.fmt.Println("--->n=",n) 打印:--->n= 1
2.if n<3{n=1所以条件成立}n++之后 n=2
3.遇到函数自己调用自己,开辟新栈(二)也就是test(2)
###############################################################
13.出栈二来到在栈一步骤3位置,代码往下执行fmt.Println("<----n=",n)栈一中此时变量n=3啊,所以打印:<----n= 2
14.main函数结束
test(2) 栈(二)
4.fmt.Println("--->n=",n) 打印:--->n= 2
5.if n<3{n=2所以条件成立}n++之后 n=3
6.遇到函数自己调用自己,开辟新栈(三)也就是test(3)
###############################################################
11.出栈三 来到在栈二步骤6的位置,代码往下执行fmt.Println("<----n=",n)栈二中此时变量n=3啊,所以打印:<----n= 3
12.栈(一)步骤3给我压栈的栈,我出栈就到栈(一)步骤3
test(3)栈(三)
7.fmt.Println("--->n=",n) 打印:--->n= 3
8.if n<3{n=3所以条件不成立了} n++不执行 test()也不会调用自己进行压栈
9.不压栈了就出栈,看到fmt.Println("<----n=",n)就执行所以打印:<----n= 3
10.然后出栈,步骤6给我压栈的栈,我出栈了就从步骤6 出去
*/
文件夹&递归思想
递归思想对我们影响深远,每天打开电脑进入文件夹、查找子文件、进入子文件 也算得上是递归操作
递:进入1个目录 ------>进入这个目录的子目---------> 进入子目录的子目录......
临界值:找到/看到自己想要的
归:再逐步退出来
rm -rf /* 中的 -r 选项是什么意思?
-r, -R, --recursive remove directories and their contents recursively
import os
file_info=[]
def recursion_files(inital_path="D:goproject"):
files = os.listdir(inital_path)
if not files:
return
for item in files:
fileAbs = os.path.join(inital_path,item)
if os.path.isfile(fileAbs):
file_info.append(fileAbs)
else:
#如果有文件夹就把该文件夹下的子目录保存进行压栈操作
recursion_files(inital_path=fileAbs)
recursion_files()
print(file_info)
阶乘
package main
import "fmt"
func f(n int) int {
if n <= 1 {
return 1
}
return n*f(n-1)
}
func main() {
ret:=f(5)
fmt.Println(ret)
}
有N个台阶,1次可以走1步,也可以走2步,请问有多少种走法?
package main
import "fmt"
func f(n int) int {
if n == 1 {
return 1
}
if n == 2 {
return 2
}
return f(n-1) + f(n-2)
}
func main() {
ret := f(3)
fmt.Println(ret)
}
defer关键字
在Go的函数里可以声明defer关键字,有延迟调用的效果,多用于文件句柄、soket资源释放。
声明1个defer就是开辟1个独立的栈,在函数体内语句执行完后在按顺序出栈。
defer的执行步骤如下:
1.先执行函数中语句内容
2.遇到defer关键字 开辟独立的defer栈空间(不同于函数)逐一压栈(不执行)
3.给函数中return值=赋值
4.按先入后出的顺序 执行defer栈中的语句内容
package main
import "fmt"
func f1() int {
x := 5
defer func() {
x++ //
}()
return x
}
func f2() (x int) {
defer func() {
x++
}()
return 5 //1.先给返回值赋值 x=5 2.defer压栈x=5 3.执行x=5+1 4.return x=6
}
func f3() (y int) {
x := 5
defer func() { //压栈时开辟了独立的空间x=5 x+1
x++
}()
return x //这里是x=y=5
}
func f4() (x int) {
defer func(x int) {
x++ //参数改写的是副本
}(x)
return 5 //1.先给返回值赋值x=5 2.defer开辟独立的栈 压栈x=5 3.执行x++ 4.returm
}
func main() {
fmt.Println(f1()) //5
fmt.Println(f2()) //6
fmt.Println(f3()) //5
fmt.Println(f4()) //5
}
当defer的函数语句中遇到函数先执行再压栈
package main
import "fmt"
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
a := 1
b := 2
//1.先执行calc("10", a, b)打印"10" 1 3 4
//2.压栈1 defer calc("1", a, 4)
defer calc("1", a, calc("10", a, b))
a=0
//3.再执行calc("20", a, b)打印"20" 0 2 2
//4.压栈2:defer calc("2", 0, 2)
defer calc("2", a, calc("20", a, b))
//栈2出栈:2 0 2 2
//栈1出栈:1 1 3 4
b=1
}
分金币
package main
import "fmt"
var (
coins = 50
users = []string{
"Matthew", "Sarah", "Augustus", "Heidi", "Emilie", "Peter", "Giana", "Adriano", "Aaron", "Elizabeth",
}
distribution = make(map[string]int, len(users))
)
/*
你有50枚金币,需要分配给以下几个人:Matthew,Sarah,Augustus,Heidi,Emilie,Peter,Giana,Adriano,Aaron,Elizabeth。
分配规则如下:
a. 名字中每包含1个'e'或'E'分1枚金币
b. 名字中每包含1个'i'或'I'分2枚金币
c. 名字中每包含1个'o'或'O'分3枚金币
d: 名字中每包含1个'u'或'U'分4枚金币
写一个程序,计算每个用户分到多少金币,以及最后剩余多少金币?
程序结构如下,请实现 ‘dispatchCoin’ 函数
*/
func dispatchCoins() {
for _, user := range users {
for _, c := range user {
switch c {
case 'e', 'E':
distribution[user]++
coins--
case 'i', 'I':
distribution[user] += 2
coins -= 2
case 'o', 'O':
distribution[user] += 3 //分金币
coins -= 3 //分出金币之后需要从总金币数量扣除
case 'u', 'U':
distribution[user] += 4
coins -= 4
}
}
}
fmt.Println(distribution) //打印每人分到的金币
fmt.Println("剩余", coins) //剩余的金币
}
func main() {
dispatchCoins()
}