函数
函数简介
函数是go语言中的一级公民,我们把所有有的功能菜单都定义在函数中,可以重复使用,函数包含函数的名称,参数列表和返回值类型,这些构成了函数的签名(signature)。
go语言中函数特性
1.go语言中有三种函数:普通函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)。
2.go语言中不允许函数重载(overload),也就是说不允许函数重名。
3.go语言中函数不能嵌套函数,但可以嵌套匿名函数。
4.函数是一个值,可以将函数赋值给变量,使得这个函数成为变量。
5.函数可以参数传递给另一个函数。
6.函数得到返回值可以是一个函数。
7.函数调用的时候,如果有参数传递给函数,则先拷贝参数的副本,再将副本传递给函数。
8.函数参数可以没有名称。
go语言中函数的定义和调用
函数在使用前必须选定义,可以调用函数来完成某个任务。函数可以重复调用,从而达到代码重用。
go语言函数定义语法
func name([list])[return_types] {
函数体
}
语法解析
- func : 函数由func开始声明
- name : 函数名称,函数名和参数列表一起构成了函数签名
- list : 参数列表,参数就行一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
- return_types : 返回类型,函数返回一列值。return_types是该列值得数据类型。有些功能不需要返回值,这种情况下return_types不是必须的。
- 函数体 : 函数定义的代码集合
函数定义的实例
- 定义一个求和函数
package main
import "fmt"
func sum(a int, b int) (ret int) {
ret = a + b
return ret
}
func main() {
r := sum(1, 2)
fmt.Printf("r=%v\n", r)
}
- 定义一个比较两个数大小的函数
package main
import (
"fmt"
)
func compare(a int, b int) (max int) {
if a > b {
max = a
} else {
max = b
}
return max
}
func main() {
r := compare(1, 2)
fmt.Printf("max=%v\n", r)
}
函数的调用
当我们要完成某个任务时,可以调用函数来完成。调用函数要传递参数,如有返回值可以获取返回值。
func main() {
r := compare(1, 2)
fmt.Printf("max=%v\n", r)
r = sum(1, 2)
fmt.Printf("r=%v\n", r)
}
函数的返回值
函数可以有0或者多个返回值,返回值需要指定数据类型,返回值通过return关键字来指定。return可以有参数,也可以没有参数,这些返回值可以有名称,也可以没有名称。go中的函数可以有多个返回值。
1.return关键字中指定了参数时,返回值可以不用名称。如果return省略参数,则返回值部分必须带名称
2.当返回值有名称时,必须使用括号包围,逗号分割,即使只有一个返回值
3.即使返回值命名了,return中也可以强制指定其他返回值的名称,也就是说return的优先级更高
4.命名的返回值是预先声明好的 ,在函数内部可以直接使用,无需再次声明。命名返回值的名称不能和函数参数名称相同,否则报错提示变量重复定义
5.return中可以有表达式,但不能出现赋值表达式,这和其他语言可能有所不同。:例如return a+b是正确的,但return c=a+b是错误的
没有返回值
package main
import "fmt"
func hhh() {
fmt.Println("我既没有返回值也没有参数!!!")
}
func main() {
hhh()
}
有一个返回值
func hhh(a int, b int) (ret int) {
ret = a + b
return ret
}
- 多个返回值且在return中指定返回的内容
package main
import "fmt"
func hhh() (name string, age string) {
name = "hhh"
age = "20"
return name, age
}
func main() {
name, age := hhh()
fmt.Printf("name:%v\n", name)
fmt.Printf("age:%v\n", age)
}
- 多个返回值,返回值名称没有被使用
package main
import "fmt"
func hhh() (name string, age string) {
name = "hhh"
age = "20"
return //等价于return name age
}
func main() {
name, age := hhh()
fmt.Printf("name:%v\n", name)
fmt.Printf("age:%v\n", age)
}
- return覆盖命名返回值,返回值名称没有被使用
package main
import "fmt"
func hhh() (string, int) {
n := "hhh"
a := 20
return n, a
}
func main() {
name, age := hhh()
fmt.Printf("name:%v\n", name)
fmt.Printf("age:%v\n", age)
}
函数的参数
go语言函数可以有0个或者多个参数,参数需要指定数据类型。
声明函数时的参数列表叫做形参,调用时传递的参数叫做实参。
go语言是通过传值的方式传参的,意味着传递给函数的是拷贝后的副本,所以函数内部访问,修改的也是这个副本。
go语言可以使用变长参数,有时候并不能确定参数的个数,可以使用变长参数,可以在函数定义语句的参数部分使用ARGS…TYPE的方式。这时将会…代表的参数全部保存到一个名为ARGS的slice中,注意这些参数的数据类型都是TYPE.
package main
import "fmt"
//这时候a,b是形参
func hhh(a int, b int) int {
return a + b
}
func main() {
//这时候是实参
qaz := hhh(1, 2)
fmt.Printf("a+b=%v\n", qaz)
}
- 演示参数传递 按值传递
package main
import "fmt"
func hhh(a int) {
a = 100
}
func main() {
x := 200
hhh(x)
fmt.Printf("x:%v\n", x)
}
- 变长参数
package main
import "fmt"
func hhh(args ...int) {
for _, i := range args {
fmt.Printf("i:%v\n", i)
}
}
func main() {
hhh(1, 2, 3, 4, 5, 6, 7)
}
package main
import "fmt"
func hhh(name string, age int, email string, args ...int) {
fmt.Printf("name=%v\n", name)
fmt.Printf("age=%v\n", age)
fmt.Printf("email=%v\n", email)
fmt.Printf("%v\n", args)
}
func main() {
hhh("hhh", 20, "hhh@qq.com", 1, 2, 3, 4, 5, 6)
}
函数类型和函数变量
可以使用type关键字来定义一个函数类型,语法个数
type fun func(int,int)int
fun 就是名称随意的
上面语句定义了一个fun函数类型,它是一种数据类型,这种函数接收两个int类型的参数并且返回一个int类型的返回值
下面我们定义两个这样结构的两个函数,一个求和,一个比较大小
package main
import "fmt"
func sum(a int, b int) int {
return a + b
}
func max(a int, b int) int {
if a > b {
return a
} else {
return b
}
}
func main() {
type hhh1 func(int, int) int
var qaz hhh1
qaz = max
c := qaz(1, 2)
fmt.Printf("c:%v\n", c)
qaz = sum
c = qaz(1, 2)
fmt.Printf("c:%v\n", c)
}
高阶函数
go语言的函数,可以作为函数的参数,传递给另外一个函数,作为另外一个函数的返回值返回
- go语言函数作为参数
package main
import "fmt"
func hhh(name string) {
fmt.Printf("Hello %v", name)
}
func hh(name string, ff func(name string)) {
ff(name)
}
func main() {
hh("hhh", hhh)
}
- 函数作为返回值
package main
import "fmt"
func add(a int, b int) int {
return a + b
}
func sub(a int, b int) int {
return a - b
}
func cal(operator string) func(int, int) int {
switch operator {
case "+":
return add
case "-":
return sub
default:
return nil
}
}
func main() {
ff := cal("+")
r := ff(1, 2)
fmt.Printf("r:%v\n", r)
ff = cal("-")
r = ff(1, 2)
fmt.Printf("r:%v\n", r)
}
- 匿名函数
go语言中函数不能嵌套,但是在函数内部可以定义匿名函数,实现以下简单调用。
所谓匿名函数就是,没有名称的函数
语法格式如下:
func (参数列表)(返回值)
也可以既没有参数,也没有返回值
//匿名函数
package main
import "fmt"
func main() {
max := func(a int, b int) int {
if a > b {
return a
} else {
return b
}
}
r := max(1, 2)
fmt.Printf("r:%v\n", r)
}
//自己调用
package main
import "fmt"
func main() {
hhh := func(a int, b int) int {
if a > b {
return a
} else {
return b
}
}(1, 2)
fmt.Printf("hhh:%v\n", hhh)
}
闭包
闭包可以理解成定义在一个函数内部的函数。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。或者说是函数和其引用环境的组合体。
闭包指的是函数和与其相关的引用环境组合而成的实体。简单来说,闭包=函数+引用环境
package main
import "fmt"
func add() func(y int) int {
var x int
return func(y int) int {
x += y
return x
}
}
//当调用add函数时add函数的返回值时匿名函数func(y int) 所以f就等于匿名函数。
//当r := f(10)时相当于调用匿名函数。
func main() {
f := add()
r := f(10)
fmt.Printf("c:%v\n", r)
r = f(20)
fmt.Printf("c:%v\n", r)
r = f(30)
fmt.Printf("c:%v\n", r)
fmt.Println("-----------------")
f1 := add()
r = f1(10)
fmt.Printf("c1:%v\n", r)
r = f1(20)
fmt.Printf("c1:%v\n", r)
}
变量f是一个函数并且它引用了其他外部作用域中的x变量,此时f就是一个闭包。在f的生命周期内,变量x也一直有效
package main
import "fmt"
func hhh(base int) (func(int) int, func(int) int) {
add := func(a int) int {
base += a
return base
}
sub := func(a int) int {
base -= a
return base
}
return add, sub
}
func main() {
add, sub := hhh(100)
r := add(100)
fmt.Printf("r:%v\n", r)
r = sub(50)
fmt.Printf("r:%v\n", r)
}
递归
函数内部调用函数自身的函数称为递归函数。
使用递归函数最重要的三点
1.递归就是自己调用自己
2.必须先定义函数的退出条件,没有退出条件,递归将成为死循环。
3.go语言递归函数很有可能会产生一大堆的goroutine,也很有可能会出现栈空间内存溢出。
//for 循环阶乘
package main
import "fmt"
func hhh() {
var s int = 1
for i := 1; i <= 5; i++ {
s *= i
}
fmt.Printf("s%v\n", s)
}
func main() {
hhh()
}
// 递归
package main
import "fmt"
func hhh(a int) int {
if a == 1 {
return 1
} else {
return a * hhh(a-1)
}
}
func main() {
c := hhh(5)
fmt.Printf("c:%v\n", c)
}
//斐波那契数列
//计算公式为 : f(n)=f(n-1)+f(n-2)且f(2)=f(1)=1
package main
import "fmt"
func hhh(a int) int {
if a == 1 || a == 2 {
return 1
}
return hhh(a-1) + hhh(a-2)
}
func main() {
c := hhh(5)
fmt.Printf("c%v\n", c)
}