函数

1|0一、什么是函数

  • 简单来说就是一个特定的方法,通过这个方法产生预期的结果。
  • 函数是一块执行特定任务的代码。一个函数是在输入源基础上,通过执行一系列的算法,生成预期的输出

2|0二、函数的定义

1. 定义函数的语法 func 函数名(参数1 参数1类型,参数2 参数2类型) 返回值类型 { // 函数体(代码块) } 1.1 若参数类型一致或返回值类型一致,则可简写 func 函数名(参数1,参数2 参数类型) (返回值1,返回值2 返回值类型) { // 函数体(代码块) } 1.2 示例,定义一个计算总价的函数 func calculateBill(price int, no int) int { var totalPrice = price * no // 商品总价 = 商品单价 * 数量 return totalPrice // 返回总价 } 2. *****************函数中的参数列表和返回值并非是必须的,所以下面这个函数的声明也是有效的*************** func test1() { // 译注: 表示这个函数不需要输入参数,且没有返回值 } 3. 若参数或者返回值都为同一个类型的,则可以简写 func 函数名(参数1,参数2 参数类型...) 返回值类型 { // 函数体(代码块) }

3|0三、函数的参数

  • 注意:函数的参数传递都是拷贝传递,相当于将参数的值拷贝一份,传入函数,所以要想在函数内部同步修改参数本身,就要用到指针

  • 和python不同的是,go中没有位置参数和关键字参数的概念,go中都是按照位置传参

  • 只需要熟悉 可变长参数函数

  • 函数作为参数

    • func add(x, y int) int { return x + y } func calc(x, y int, op func(int, int) int) int { return op(x, y) } func main() { ret2 := calc(10, 20, add) fmt.Println(ret2) //30 }

4|0四、函数的返回值

  • 和python不同的是,GO中对函数的返回值的类型也必须提前写死
  • 想接收一个函数的返回值,该函数有几个返回值必须要声明几个变量来接收,也可以用匿名变量(或者叫空白符) _ 来接收某个返回值

4|11. 多个返回值

  • go中是支持多个返回值的,返回值类型用括号括起来即可
1. 语法是 func 函数名(参数1 参数1类型,参数2 参数2类型) (返回值1类型,返回值2类型) { // 函数体(代码块) return1,值2... } 1.1 示例,定义一个计算矩形的周长和面积的函数 package main import ( "fmt" ) func rectProps(length, width float64)(float64, float64) { var area = length * width var perimeter = (length + width) * 2 return area, perimeter } func main() { area, perimeter := rectProps(10.8, 5.6) fmt.Printf("Area %f Perimeter %f", area, perimeter) }

4|22. 命名返回值

  • 在定义函数时,若指定了返回值的变量名,则在函数体中,也不用重新声明该返回的变量,不需要再明确指定返回值
1. 若返回值都为同一个类型的,则可以简写 func 函数名(参数1,参数2 参数类型) (返回值1,返回值2 返回值类型) { // 函数体(代码块) } 1.1 如下面的rectProps方法 func rectProps(length float64, width float64)(area float64, perimeter float64) { area = length * width perimeter = (length + width) * 2 return // 不需要明确指定返回值,默认返回 area, perimeter 的值 } 1.1.1 可以简写为: func rectProps(length, width float64)(area, perimeter float64) { area = length * width // 直接赋值,不用声明 perimeter = (length + width) * 2 // 直接赋值,不用声明 return // 不需要明确指定返回值,默认返回 area, perimeter 的值 }

4|33. 返回值补充

1|0(1)nil作为返回值时

  • 当我们的一个函数返回值类型为切片时,nil可以看做是一个有效的,没必要显示返回一个长度为0的切片

    • 其他空值也为nil的如 map 、指针等,也同样适用上述规则
    func someFunc(x string) []int { if x == "" { return nil // 没必要返回[]int{} } ... }

1|0(2)函数作为返回值

func do(s string) (func(int, int) int, error) { switch s { case "+": return add, nil case "-": return sub, nil default: err := errors.New("无法识别的操作符") return nil, err } }

5|0五、匿名函数

  • 和python中的匿名函数,差别很大,Go中的匿名函数没有关键字,相当于用变量去存储一个没名字的正常函数,代码格式类似python中的闭包函数
  • 同普通函数一样,匿名函数的参数类型和返回值的类型都是该匿名函数类型的一部分
  • 匿名函数因为没有函数名,所以没办法像普通函数那样调用,所以匿名函数需要保存到某个变量或者作为立即执行函数

5|11. 匿名函数的定义

  • 匿名函数因为没有函数名,所以没办法像普通函数那样调用,所以匿名函数需要保存到某个变量或者作为立即执行函数

  • 加括号可以直接调用

  • 下面是没有返回值的闭包函数

语法: 变量名 := func(参数 类型) 返回值类型{函数体} // 示例: package main import ( "fmt" ) func main() { // 将匿名函数保存到变量 add := func(x, y int) { fmt.Println(x + y) } add(10, 20) // 通过变量调用匿名函数 //自执行函数:匿名函数定义完加()直接执行 func(x, y int) { fmt.Println(x + y) }(10, 20) }

5|22. 闭包函数

  • 闭包函数指的是一个函数和它引用环境组合在一起,形成的一个组合体,该组合体称为闭包函数。简而言之,闭包函数=函数+引用环境

  • 闭包一定是嵌套函数,但嵌套函数不一定是闭包函数

  • 闭包函数的概念就使得其有个特点,即在闭包函数的内部,对外层的作用域有引用。意思就是闭包函数内部使用外层的变量都是使用的地址,而非拷贝的值

package main import ( "fmt" ) func test3(a, b int) func(a, b string) (int, int, int) { fmt.Println("test3 a,b:", a, b) fmt.Printf("test3 a,b的地址: %p %p\n", &a, &b) // %p 的作用是打印地址 f := func(x, y string) (int, int, int) { fmt.Println("x,y:", x, y) fmt.Printf("匿名函数内部 a,b的地址: %p %p\n", &a, &b) return 3, 4, 5 } return f } func main() { a, b := 1, 2 println("外部a,b地址:", &a, &b) f := test3(a, b) fmt.Println("f:", f) f("xxx", "yyy") } /* 打印结果: 外部a,b地址: 0xc000107f10 0xc000107f08 test3 a,b: 1 2 test3 a,b的地址: 0xc00000a0d8 0xc00000a0f0 f: 0xafb1a0 x,y: xxx yyy 匿名函数内部 a,b的地址: 0xc00000a0d8 0xc00000a0f0 可以看出,test3 a,b的地址 和 匿名函数内部 a,b的地址 是一样的,但它们和test3外部的x,y的地址是不同的 */

1|0(1)闭包函数简单示例

package main import ( "fmt" ) func adder() func(int) int { var x int return func(y int) int { x += y return x } } func main() { var f = adder() fmt.Println(f(10)) //10 fmt.Println(f(20)) //30 fmt.Println(f(30)) //60 f1 := adder() fmt.Println(f1(40)) //40 fmt.Println(f1(50)) //90 } // 注意每次的打印结果

1|0(2)闭包函数进阶示例

1|0i. 示例1

package main import ( "fmt" ) func adder2(x int) func(int) int { return func(y int) int { x += y return x } } func main() { var f = adder2(10) fmt.Println(f(10)) //20 fmt.Println(f(20)) //40 fmt.Println(f(30)) //70 f1 := adder2(20) fmt.Println(f1(40)) //60 fmt.Println(f1(50)) //110 } // 注意每次的打印结果

1|0ii. 示例2

package main import ( "fmt" ) func makeSuffixFunc(suffix string) func(string) string { return func(name string) string { if !strings.HasSuffix(name, suffix) { return name + suffix } return name } } func main() { jpgFunc := makeSuffixFunc(".jpg") txtFunc := makeSuffixFunc(".txt") fmt.Println(jpgFunc("test")) //test.jpg fmt.Println(txtFunc("test")) //test.txt } // 注意每次的打印结果

1|0iii. 示例3

package main import ( "fmt" ) func calc(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 := calc(10) fmt.Println(f1(1), f2(2)) //11 9 fmt.Println(f1(3), f2(4)) //12 8 fmt.Println(f1(5), f2(6)) //13 7 } // 注意每次的打印结果

__EOF__

本文作者BigSun丶
本文链接https://www.cnblogs.com/Mcoming/p/18025484.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   BigSun丶  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示