函数
1. 定义格式
- 基本组成:关键字func、函数名、参数列表、返回值、函数体和返回语句
- 只有一个返回值且不声明变量,可以省略括号
2. 自定义函数
1. 无参无返回值
func TestFunc() {
a := 2
fmt.Println("This is a test func, a is ", a)
}
func main() {
TestFunc() //无参无返回值函数调用
}
2. 有参无返回值
1). 普通参数列表
- 定义函数时,在函数名后边 ( ) 定义的参数叫形参
- 调用函数传递的参数叫实参
- 参数传递,只能由实参传递给形参
func TestFunc1(a, b int) { fmt.Println("a = ", a) fmt.Println("b = ", b) } func main() { TestFunc1(0, 12) }
2). 不定参数列表
-
不定参数类型
-
指函数传入的参数个数为不定数量
-
需要将函数定义为接受不定参数类型
-
传递的实参可以是0或多个
func TestFunc(args ...int){ fmt.Println(len(args)) }
-
-
不定参数的传递
func func1(tmp ...int) { for _, data := range tmp{ fmt.Printin(data) } } func func2(tmp ...int) { for _, data := range tmp{ fmt.Printin(data) } } func Test(args ... int) { // 全部参数传递给Test func1(args...) // 只把后两个参数传递 // func2(args[2:]...) } func main() { Test(1, 2, 3, 4) }
3. 无参有返回值
- 有返回值的函数,必须有明确的终止语句
- 官方建议,最好命名返回值
- 1). 一个返回值
func Test() int{ return 123 } // 给返回值命名 func TestName() (v int) { v = 1 return v // 也可直接return }
- 2). 多个返回值
func Test() (a b, int, c string){ a, b = 1, 2 c = 'str' return }
4. 有参有返回值
3. 递归函数
4. 函数类型
- 函数也是一种数据类型
- 通过type来定义
func Add(a, b, int) int {
return a + b
}
type FuncName func(int, int) int
func main() {
var fTest FuncName
fTest = Add
result = fTest(10, 20) // 等价于Add(10, 20)
}
- 回调函数
- 函数有一个参数是函数类型,就是回调函数
type FuncType func(int, int) int func Add(a, b, int) int { return a + b } func Calc(a, b int, f FuncType) (result int) { result = f(a, b) return } func main() { a := Calc(1, 1, Add) }
- 函数有一个参数是函数类型,就是回调函数
5. 匿名函数与闭包
- 匿名函数:没有函数名字
- 函数的返回值是一个匿名函数,返回一个函数类型
- 闭包
- 以引用方式捕获外部变量
- 闭包不关心变量和常量是否超出作用域,只要闭包还在使用,这些变量还会存在
- (变量的生命周期不是由它的作用域决定,变量仍隐式存在于函数中)
6. 延迟调用defer
1. defer的作用
- 关键字defer用于延迟一个函数或方法
- 只能出现在函数或方法的内部
2. 多个defer执行顺序
- 后进先出的顺序执行
- 哪怕函数或某个延迟调用发生错误,这些调用仍旧会被执行
3. defer与匿名函数结合使用
func main() {
a, b := 10, 20
defer func(x int) {
fmt.Println("defer:", x, b) // b 闭包引用
}(a)
a += 10
b += 100
fmt.Printf("a = %d, b = %d\n", a, b)
/*
运行结果:
a = 20, b = 120
defer: 10 120
*/
}
7. 获取命令行参数
package main
import (
"fmt"
"os"
)
func main() {
args := os.Args //获取用户输入的所有参数
//如果用户没有输入,或参数个数不够,则调用该函数提示用户
if args == nil || len(args) < 2 {
fmt.Println("err: xxx ip port")
return
}
ip := args[1] //获取输入的第一个参数
port := args[2] //获取输入的第二个参数
fmt.Printf("ip = %s, port = %s\n", ip, port)
}
8. 作用域
- 作用域为已声明标识符所表示的常量、类型、变量,函数或包在源代码中的作用范围
1. 局部变量
- 定义在 { } 里面的变量就是局部变量,只能在 { } 里有效
- 执行到定义变量那句时,才开始分配空间,离开作用域会自动释放
2. 全局变量
- 在函数体外声明的变量称之为全局变量
- 全局变量可以在整个包甚至外部包(被导出后)使用
3. 不同作用域同名变量
- 在不同作用域可以声明同名的变量
- 其访问原则为:
- 在同一个作用域内,就近原则访问最近的变量
- 如果此作用域没有此变量声明,则访问全局变量
- 如果全局变量也没有,则报错。