3.函数
3.1函数定义
3.2变参
3.3返回值
3.4匿名函数
3.5延迟调用
3.6错误处理
1.函数是第一类对象,可作为参数传递。建议将复杂签名定义为函数类型,以便于阅读。
package main
import "fmt"
func test(fn func() int) int {
return fn()
}
type FormatFunc func(s string, x,y int) string //定义函数原型
func format(fn FormatFunc,s string, x,y int) string {
return fn(s,x,y)
}
func main() {
s1:=test(func() int {return 100}) //直接将匿名函数当参数
s2:=format(func(s string,x,y int)string {
return fmt.Sprintf(s,x,y)
},"caonima %d,%d rinidie",10,20)
fmt.Println(s1,s2)//输出:100 caonima 10,20 rinidie
}
func test(s string, n ...int) string {
var x int
for _, i := range n {
x += i
}
return fmt.Sprintf(s, x)
}
func main() {
println(test("sum: %d", 1, 2, 3))
}
使用slice对象做变参时,必须展开。
func main() {
s := []int{1, 2, 3}
println(test("sum: %d", s...))
}
func test() (int, int) {
return 1, 2
}
func main() {
// s := make([]int, 2)
// s = test() // Error: multiple-value test() in single-value context
x, _ := test()
println(x)
}
4.命名返回参数允许defer延迟调用通过闭包读取和修改
func add(x, y int) (z int) {
defer func() {
z += 100
}()
z = x + y
return
}
func main() {
println(add(1, 2)) // 输出: 103
}
显示return返回前,会先修改命名返回参数。
func add(x, y int) (z int) {
defer func() {
println(z) // 输出: 203
}()
z = x + y
return z + 200 // 执⾏顺序: (z = z + 200) -> (call defer) -> (ret)
}
func main() {
println(add(1, 2)) // 输出: 203
}
5.匿名函数可赋值给变量,做为结构字段,或者在 channel 里传送。
// --- function variable ---
fn := func() { println("Hello, World!") }
fn()
// --- function collection ---
fns := [](func(x int) int){
func(x int) int { return x + 1 },
func(x int) int { return x + 2 },
println(fns[0](100))
// --- function as field ---
d := struct {
fn func() string
}{
fn: func() string { return "Hello, World!" },
}
println(d.fn())
// --- channel of function ---
fc := make(chan func() string, 2)
fc <- func() string { return "Hello, World!" }
println((<-fc)())
6.关键字 defer 用于注册延迟调用。这些调用直到 ret 前才被执行,通常用于释放资源或错误处理。
多个 defer 注册,按 FILO 次序执行。哪怕函数或某个延迟调用发生错误,这些调用依旧会被执行。
func test(x int) {
defer println("a")
defer println("b")
defer func() {
println(100 / x) // div0 异常未被捕获,逐步往外传递,最终终⽌进程。
}()
defer println("c")
}
func main() {
test(0)
}
输出:
c b a
panic: runtime error: integer divide by zero
7..没有结构化异常,使用 panic 抛出错误, recover 捕获错误。
func test() {
defer func(){
if err:=recover();err!=nil{
fmt.Println(err.(string))
}
}()
panic("panic error")
}
延迟调用中引发的错误,可被后续延迟调用捕获,但仅最后一个错误可被捕获。
捕获函数 recover 只有在延迟调用内直接调用才会终止错误,否则总是返回 nil。任何未捕获的错误都会沿调用堆栈向外传递。
导致关键流程出现不可修复性错误的使用panic,其他使用 error