文章目录
1. 函数的定义
- 当参数类型相同时,可以省略掉前面的类型
- 想传递给函数的参数不能确定有多少时,可使用变长参数 => 变长参数必须放在函数参数的最后
func function_name([parameter list]) [return _types]{
// 函数体
}
1.1 简单栗子 - max()
函数
package main
import "fmt"
func main() {
fmt.Println(max(2, 3))
}
func max(num1, num2 int) int {
if num1 > num2 {
return num1
}
return num2
}
1.2 多返回值
通过返回结果与一个错误值,可以使函数调用者知道函数是否执行成功,这也称为command,ok模式(推荐)
package main
import (
"errors"
"fmt"
)
func main() {
result, err := div(1, 2)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Println("result: ", result)
}
func div(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("the divisor cannot be zero")
}
return a / b, nil
}
1.3 给返回值命名
需要返回的时候,我们只需要一条简单的不带参数的return语句
func div(a, b float64) (result float64, err error) {
if b == 0 {
return 0, errors.New("被除数不能等于0")
}
result = a / b
return
}
2. 函数的参数和调用
形参就像定义在函数体内的局部变量
调用函数,可通过两种方式来传递参数:
- 值传递:将实际参数复制一份传递到函数中 => 在函数中修改参数,不会影响实际参数
- 引用传递:将实际参数的地址传递到函数中 => 修改参数,会影响实际参数
默认情况下,Go 语言使用值传递。
package main
import "fmt"
func main() {
a := 1
b := 1
c := []int{1, 2, 3}
paramFunc(a, &b, c)
fmt.Println("main:")
fmt.Println(a) // 未变
fmt.Println(b) // 变了
fmt.Println(c) // 变了
}
func paramFunc(a int, b *int, c []int) {
a = 100
*b = 100
c[1] = 100
fmt.Println("paramFunc:")
fmt.Println(a)
fmt.Println(*b)
fmt.Println(c)
}
3. 函数的用法
3.1 函数的作为实参
函数定义后可作为另外一个函数的实参数传入
1)该函数仅是为了使用内置函数math.sqrt()
package main
import (
"fmt"
"math"
)
func main() {
getSquareRoot := func(x float64) float64 {
return math.Sqrt(x)
}
fmt.Println(getSquareRoot(9))
}
2)函数作为参数传递,实现回调
package main
import (
"fmt"
)
func main() {
callBack0(1, callBack)
callBack0(2, func(x int) int {
fmt.Printf("I'm callback:%d\n", x)
return x
})
}
type cb func(int) int
func callBack0(x int, f cb) {
f(x)
}
func callBack(x int) int {
fmt.Printf("I'm callback:%d\n", x)
return x
}
3.2 闭包
Go 支持匿名函数,可作为闭包(匿名函数可直接使用函数内的变量,不必申明)
- 闭包:一个函数与这个函数外部变量的一个封装
- 闭包:一个类 - 类里有变量和方法,其中闭包所包含的外部变量对应着类中的静态变量
- 闭包通过操作指针来调用对应的变量
package main
import "fmt"
func main() {
nextNumber := getSequence() // nextNumber为一个函数 - i=0
fmt.Println(nextNumber()) //1
fmt.Println(nextNumber()) //2
fmt.Println(nextNumber()) //3
nextNumber1 := getSequence()
fmt.Println(nextNumber1()) //1
fmt.Println(nextNumber1()) //2
}
func getSequence() func() int {
i := 0
return func() int {
i++
return i
}
}
带参数的闭包
package main
import "fmt"
func main() {
addFunc := add(1, 2)
fmt.Println(addFunc()) //1 3
fmt.Println(addFunc()) //2 3
fmt.Println(addFunc()) //3 3
}
func add(x, y int) func() (int, int) {
i := 0
return func() (int, int) {
i++
return i, x + y
}
}
3.3 函数方法
package main
import "fmt"
// Circle - define structure
type Circle struct {
radius float64
}
func main() {
var c1 Circle
c1.radius = 10.00
fmt.Println("圆的面积 = ", c1.getArea())
}
func (c Circle) getArea() float64 {
return 3.14 * c.radius * c.radius
}
4. 小练习
4.1 栗子 - 值传递
在函数中修改参数,不会影响实际参数
package main
import "fmt"
func main() {
x := 100
y := 200
z := swap(x, y)
// 100, 100, 200
fmt.Printf("z的值为:%d; 交换后的x:%d; 交换后的y:%d", z, x, y)
}
func swap(x, y int) int {
temp := x
x = y
y = temp
return temp
}
4.2 栗子 - 引用传递
在函数中修改参数,会影响实际参数
&x 指向 x 指针,x 变量的地址
package main
import "fmt"
func main() {
x := 100
y := 200
swap(&x, &y)
// 200, 100
fmt.Printf("交换后的x:%d; 交换后的y:%d", x, y)
}
func swap(x *int, y *int) {
*x, *y = *y, *x
}
4.3 函数返回多个值
package main
import "fmt"
func main() {
fmt.Println(swap("haha1", "haha2"))
}
func swap(x, y string) (string, string) {
return y, x
}
4.4 闭包实现斐波那契
package main
import "fmt"
func main() {
f := fibonacci()
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
}
func fibonacci() func() int {
x, y := 0, 1
return func() int {
x, y = y, x+y
return x
}
}