函数
是执行特定公开、可复用的代码块,包括函数、匿名函数、闭包。可作为变量、返回值、参数等。
func 函数名(参数)(返回值){
函数体
}
函数名:字母、数字、下划线组成,第一个字母不能是数字;同一个包内,函数名也不能重名;
返回值:可返回多个返回值,必须用()
包裹,并用,
分隔
函数定义与使用
func testOne(){
fmt.Println("Hello")
}
func testTwo(x int){
fmt.Println(x)
}
//多个同类型的参数,可省略前面的类型
func testThree(x, y int){
fmt.Println(x, y)
}
func testSum(x int, y int)int{
ret := x + y
return ret
}
func testSum2(x int, y int)(ret int){
ret = x + y
return
}
//可变参数,在函数体中是切片类型
//固定参数和可变参数一起出现时候,可变参数必须放到最后
//go语言中没有默认参数
func testSum3(a int, x ...int)int{
fmt.Printf("tyep:%T,content:%v\n", a, a)
fmt.Printf("tyep:%T,content:%v\n", x, x)
sum := 0
for _, value := range x {
sum += value
// sum = testSum2(sum, value)
}
return sum
}
//多个返回值情况,必须用括号包起来
//多个返回值,也支持参数简写
func calc(a, b int)(sum, sub int){
sum = a + b
sub = a - b
return
}
func main() {
testOne()
testTwo(2)
testThree(3, 3)
fmt.Println(testSum(1, 1))
fmt.Println(testSum2(2, 2))
sum1 := testSum3(1, 2, 3, 4, 5);
fmt.Println(sum1)
sum2 := testSum3(1, 2, 3, 4);
fmt.Println(sum2)
sum3 := testSum3(1);
fmt.Println(sum3)
sum, sub := calc(100, 200)
fmt.Println(sum, sub)
}
defer语句
将其后面跟随的语句进行延迟处理,在defer
归属的函数即将返回时,将延迟处理的语句按照defer
定义的逆序进行执行(先被defer
的语句最后执行,最后被defer
语句,最先被执行)。
defer语句非常方便处理资源释放问题,比如资源清理、文件关闭、解锁及记录时间等。
//defer 延迟执行
func main() {
fmt.Println("start")
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
fmt.Println("end")
}
输出
start
end
3
2
1
经典案例
package main
import "fmt"
//1.汇编层面定义一个变量接收函数返回值
//2.return x,则这个返回变量的值为5
//3.defer指令,x++,x为6
//4.汇编层面RET指令,返回变量的值是5
func f1() int {
x := 5
defer func(){
x++
}()
return x
}
//1.汇编层面定义一个变量接收函数返回值,是x
//2.return x,则这个返回变量的值为5,x=5
//3.defer指令,x++,x=6
//4.汇编层面RET指令,返回变量的值是6(x=6)
func f2() (x int) {
defer func(){
x++
}()
return 5
}
//1.汇编层面定义一个变量接收函数返回值,是y
//2.return x,则这个返回变量的值为5,y=5
//3.defer指令,x++,x=6
//4.汇编层面RET指令,返回变量的值是5(y=5)
func f3() (y int) {
x := 5
defer func(){
x++
}()
return x
}
//1.汇编层面定义一个变量接收函数返回值,是x
//2.return x,则这个返回变量的值为5,x=5
//3.defer指令,值传递
//4.汇编层面RET指令,返回变量的值是5(x=5)
func f4() (x int) {
defer func(x int){
x++
}(x)
return 5
}
func main() {
fmt.Println(f1()) //5
fmt.Println(f2()) //6
fmt.Println(f3()) //5
fmt.Println(f4()) //5
}
作用域
- 函数内部可以访问全局变量,如果函数内部定义同名的局部变量,先取用局部变量;
- 外层不能访问函数的内部变量(局部变量);
- 外层访问不到内部for、if、switch语句块中的变量;
//定义全局变量
var num = 10
func test(){
fmt.Println("全局变量", num)
num := 20
fmt.Println("局部变量", num)
}
func main() {
test()
fmt.Println("全局变量", num)
}
输出
全局变量 10
局部变量 20
全局变量 10
函数作为变量
//定义全局变量
var num = 10
func test(){
fmt.Println("全局变量", num)
num := 20
fmt.Println("局部变量", num)
}
func main() {
//函数作为变量
abc := test
fmt.Printf("%T\n", abc)
//调用
abc()
}
输出
func()
全局变量 10
局部变量 20
函数作为参数
func add(x, y int) int {
return x + y
}
func sub(x, y int) int {
return x - y
}
func calc(x, y int, op func(int, int) int) int{
return op(x, y)
}
func main() {
add := calc(100, 200, add)
fmt.Println(add)
sub := calc(100, 200, sub)
fmt.Println(sub)
}
匿名函数
没有函数名的函数
func(参数)(返回值){
函数体
}
func main() {
//匿名函数赋值给变量
test := func(){
fmt.Println("haha")
}
test()
//匿名函数直接使用
func(){
fmt.Println("hihi")
}()
}
闭包
闭包
指的是一个函数和与其相关的引用环境组合而成的实体,即闭包=函数+引用环境
。
//函数返回值是函数
func a() func() {
name := "lv"
return func(){
fmt.Println("haha", name)
}
}
func b(name string) func() {
return func(){
fmt.Println("haha", name)
}
}
func main() {
//闭包 = 函数 + 外层变量的引用
r := a()
r() //相当于执行了a函数内部的匿名函数
c := b("c")
c()
}
常用内置函数
内置函数 | 介绍 |
---|---|
close | 主要是用来关闭channel |
len | 求长度,例如string、array、slice、map、channel |
new | 主要分配值类型内存,例如 int、struct、string、array等,返回的是指针 |
make | 主要分配引用类型的内存,比如chan、map、slice |
append | 追加元素到array、slice中 |
panic和recover | 用来错误处理 |
Go(1.12)没有异常处理,用panic
和recover
。panic
是运行时候错误。
recover
必须搭配defer
使用defer
一定要在可能引发panic
的语句之前定义
func a(){
fmt.Println("func a")
}
func b(){
defer func(){
err := recover()
if err != nil {
panic("func b error")
}
}()
panic("panic in b")
}
func c(){
fmt.Println("func c")
}
func main() {
a()
b() //程序崩溃
c()
}