Go语言基础之函数

函数

Go语言中支持函数、匿名函数和闭包

 

函数定义

func 函数名(参数)(返回值){
    函数体
}
func intSum(x, y int) int {
	return x + y
}

func helloWord() {
	fmt.Println("hello word")
}

 

函数调用

func main() {
	c := intSum(10, 20)
	fmt.Println(c)
	helloWord()
}

 

可变参数

可变参数放在固定参数后边,通过...来实现,可变参数为一个切片

func intSum(x int, y ...int) int {
	sum := x
	for _, v := range y {
		sum += v
	}
	return sum
}

 

多返回值和返回值命名

func intSum(x int, y ...int) (int, int) {
	sum := x
	sub := x
	for _, v := range y {
		sum += v
		sub -= v
	}
	return sum, sub
}

func intSum1(x, y int) (sum int) {
	sum = x + y
	return
}

 

变量作用域

全局变量:全局变量是定义在函数外部的变量,在程序运行周期内都有效。函数中可访问

package main

import "fmt"

var num int64 = 10

func test() {
	fmt.Println(num)
}
func main() {
	test()
}

局部变量:局部变量分两种,一种是在函数内定义,一种是语句块内(if、for、switch)定义。如果和全局变量同名,有限访问局部变量。

package main

import "fmt"

var num int64 = 10

func test(x int) {
	num := 100
	fmt.Println(num)
	if x > 10 {
		z := 10		// 只在if中生效
		fmt.Println(z)
	}
}
func main() {
	test(11)
}

 

函数类型与变量

定义函数类型

type calculation func(int, int) int

func add(x, y int) int {
	return x + y
}

func main() {
	var c calculation
	c = add
	num1 := c(10, 20)
	fmt.Println(num1)
}

 

高阶函数

高阶函数分为函数作为参数和函数作为返回值

 

函数作为参数

func add(x, y int) int {
	return x + y
}
func calc(x, y int, op func(int, int) int) int {
	return op(x, y)
}

func main() {
	ret := calc(10, 20, add)
	fmt.Println(ret)    // 30
}

 

函数作为返回值

func do(s string) (func(int, int) int, error) {
	switch s {
	case "+":
		return add, nil
	case "-":
		return sub, nil
	default:
		err := errors.New("无法识别的标识符")
		return nil, err
	}
}

 

匿名函数和闭包

匿名函数:匿名函数就是没有函数名的函数,如果想调用需要保在某个变量中或者立即执行函数。匿名函数多用于回调函数和闭包

func(参数)(返回值){
    函数体
}
func main() {
	add := func(x, y int) {
		fmt.Println(x + y)
	}
	add(10, 20) // 通过变量调用匿名函数

	func(x, y int) {	// 自动执行函数:匿名函数定义完加()直接执行
		fmt.Println(x + y)
	}(20, 20)
}

 

闭包:闭包指一个函数和其相关的应用环境组合而成的实体。闭包=函数+应用环境

func adder() func(int) int {
	var x int
	return func(y int) int {
		x += y
		return x
	}
}

func main() {
	var f1 = adder()
	fmt.Println(f1(10))		// 10
	fmt.Println(f1(10))		// 20

	f2 := adder()
	fmt.Println(f2(30))		// 30
	fmt.Println(f2(30))		// 60
}

变量f在一个函数并且引用了其外部作用域的x变量,此时f就是一个闭包。在f生命周期内,变量x一直有效

 

闭包一:

func adder(x int) func(int) int {
	return func(y int) int {
		x += y
		return x
	}
}

func main() {
	var f1 = adder(10)
	fmt.Println(f1(10)) // 20
	fmt.Println(f1(10)) // 30

	f2 := adder(20)
	fmt.Println(f2(30)) // 50
	fmt.Println(f2(30)) // 80
}

 

闭包二:

func makeSuffixFunc(suffix string) func(string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}
		return name
	}
}

func main() {
	jpgFunc := makeSuffixFunc(".jpg")
	txtFunc := makeSuffixFunc(".txt")
	fmt.Println(jpgFunc("图片"))
	fmt.Println(txtFunc("图书"))
}

 

闭包三:

func calc(base int) (func(int) int, func(int) int) {
	add := func(i int) int {
		base += i
		return base
	}

	sub := func(i int) int {
		base -= i
		return base
	}
	return add, sub
}

func main() {
	f1, f2 := calc(10)
	fmt.Println(f1(1), f2(1))       // 11,10
}

 

defer语句

defer语句会延迟处理,并且按照倒序执行。defer函数参数是在defer语句出现的位置做计算的,而不是在函数运行的时候做计算的,即所在函数结束的时候计算的。

func main() {
	fmt.Println("start")
	defer fmt.Println("defer1")
	defer fmt.Println("defer2")
	fmt.Println("end")
}

// 顺序为start end defer2 defer1

func foo(n int) int {
	fmt.Println("n1:", n)
	defer fmt.Println("n:", n)
	n += 100
	fmt.Println("n2:", n)
	return n
}
func main() {
	foo(100)
}
// 输出为 n1:100  n2:200  n:100

 

defer经典案例

func f1() int {
	x := 5
	defer func() {
		x++
	}()
	return x
}

func f2() (x int) {
	defer func() {
		x++
	}()
	return 5
}

func f3() (y int) {
	x := 5
	defer func() {
		x++
	}()
	return x
}
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
}

 

defer函数参数示例

func calc(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret
}

func main() {
	a := 1
	b := 2
	defer calc("1", a, calc("10", a, b))
	a = 0
	defer calc("2", a, calc("20", a, b))
	b = 1
}
// 10 1 2 3
// 20 0 2 2
// a,b 0 1
// 2 0 2 2
// 1 1 3 4
// defer后面的函数参数优先计算

 

加深理解defer函数参数是在defer语句出现的位置做计算的,而不是在函数运行的时候做计算的,即所在函数结束的时候计算的。

func foo(n int) int {
	fmt.Println("n1=", n)
	defer fmt.Println("n=", n)
	n += 100
	fmt.Println("n2=", n)
	return n
}

func main() {
	var i int = 100
	foo(i)
}

// 输出结果为 n1=100; n2=200; n=100    n为defer函数的参数
func foo(n int) int {
	fmt.Println("n1=", n)
	defer func() {
		n += 100
		fmt.Println("n=", n)
	}()
	n += 100
	fmt.Println("n2=", n)
	return n
}

func main() {
	var i int = 100
	foo(i)
}

// 结果为:n1=100; n2=200; n=300    此时的n不是defer后边的参数

 

内置函数

内置函数 介绍
close 主要用于关闭channel
len 用来求长度,比如string、array、slice、map、channel
new 用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针
make 用来分配内存,主要用来分配引用类型,比如chan、map、slice
append 用来追加元素到数组、slice中
panic和recover 用来做错误处理

make和new的区别

Go语言基础之函数_第1张图片

panic和recover

使用panic/recover模式来处理错误。panic任何地方都可以引发,但recover只能在defer调用的函数中有效

func funcA() {
	fmt.Println("func A")
}

func funcB() {
	defer func() {
		err := recover()
		//如果程序出出现了panic错误,可以通过recover恢复过来
		if err != nil {
			fmt.Println("recover in B")
		}
	}()
	panic("panic in B")
}

func funcC() {
	fmt.Println("func C")
}
func main() {
	funcA()
	funcB()
	funcC()
}

 

你可能感兴趣的:(#,go语言基础,Golang)