<10>Golang基础进阶——函数

Golang开发之函数(function)

基础

普通函数的声明形式

func 函数名(参数列表)(返回值列表) {
函数体
}

参数类型的简写

func add(a, b int) int {
return a + b
}

函数的返回值

 同一种类型返回值

使用 return 语句返回时,值列表的顺序需要与函数声明的返回值类型一致。

func typedTwoValues() (int, int) {
return 1, 2
}

func main() {
a, b := typedTwoValues()
fmt.Println(a, b)
}

 带有变量名的返回值

Go 语言支持对返回值进行命名,这样返回值就和参数一样拥有参数变量名和类型。
命名的返回值变量的默认值为类型的默认值,即数值为0,字符串为空字符串,布尔为false、指针为nil等。
下面代码中的函数拥有两个整型返回值,函数声明时将返回值命名为a和b ,因此可以在函数体中直接对函数返回值进行赋值。

func namedRetValues() (a, b int){
a = 1
b = 2

return
}

下面代码的执行效果和上面代码的效果一样:

func namedRetValues() (a, b int){
a = 1

return a, 2
}

提示: 同一种类型返回值和命名返回值两种形式只能二选一, 混用时将会发生编译错误。

func namedRetValues() (a, b int, int)

示例:将“秒”解析为时间单位

在本例中,使用一个数值表示时间中的“秒”值, 然后使用 resolveTime() 函数将传入的秒数转换为天、小时和分钟等时间单位。

const (
// 定义每分钟的秒数
SecondsPerMinute = 60

// 定义每小时的秒数
SecodesPerHour = SecondsPerMinute * 60

// 定义每天的秒数
SecodesPerDay = SecodesPerHour * 24
)

func resolveTime(seconds int) (day int, hour int, minute int){
day = seconds / SecodesPerDay
hour = seconds / SecodesPerHour
minute = seconds / SecondsPerMinute

return

}

func main() {
// 将返回值作为打印参数
fmt.Println(resolveTime(1000))

// 只获取消息和分钟
_, hour, minute := resolveTime(18000)
fmt.Println(hour, minute)

// 只获取天
day, _, _ := resolveTime(90000)
fmt.Println(day)
}

匿名函数一一没青函数名字的函数

函数也是一种类型,因此可以定义一个函数类型的变量,格式:

func (参数列表) (返回参数列表){
	函数体
}

在定义时调用匿名函数

func (data int){
	fmt.Println("hello", data)
}(100)

// "}" 后的 "(100)",表示对匿名函数进行调用,传递参数为 10

匿名函数用作回调函数 

func visit(list []int, f func(int)) {
	for _, v := range list {
		f(v)
	}
}

func main() {
	// 使用匿名函数打印切片内容
	visit([]int{1, 2, 3, 4}, func(v int) {
		fmt.Println(v)
	})
}

匿名函数作为回调函数的设计在 Go 语言的系统包中也比较常见 strings 包中就有如:

func TrimFunc(s string, f func(rune) bool) string {
	return TrimRightFunc(TrimLeftFunc(s, f), f)
}

匿名函数的简单示例

示例1:
func test2() {
	f1 := func(a, b int) int {
		return a + b
	}
	fmt.Printf("f1类型是%T
", f1)

	sum := f1(2, 3)
	fmt.Println(sum)
}

func main() {
	test2()
}
示例2:
func test3() {
	var i int = 0
	defer fmt.Printf("defer i=%d
", i)
	i = 100
	fmt.Println(i)
	return
}
func main() {
	test3()
}
 示例3:
func test4() {
	var i int = 0
	defer func() {
		fmt.Printf("defer i=%d
", i)
	}()
	i = 100
	fmt.Printf("i=%d
", i)
	return
}

func main() {
	test3()
}

函数类型作为参数

func test1(a, b int, my func(int, int) int) int {
	return my(a, b)
}

func sub(a, b int) int {
	return a - b
}

func main() {
	res := test1(30, 10, sub)
	fmt.Println(res)
}

闭包( Closure )————引用了外部变量的匿名函数

闭包是引用了自由变量的函数,即使离开了自由变量的环境也不会被删除或释放,简单说:函数+引用环境=闭包

闭包示例

示例1:

func add() func(int) int {
	var x int
	return func(d int) int {
		x += d
		return x
	}
}

func main() {
	var f = add()
	fmt.Println(f(10))
	fmt.Println(f(10))
	fmt.Println(f(10))
}

示例2:

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

func main() {
	tmp1 := add(10)
	fmt.Println(tmp1(1), tmp1(2))

	// 此时tmp1和tmp2不是一个实体了
	tmp2 := add(100)
	fmt.Println(tmp2(1), tmp2(2))
}

闭包实现生成器

// 创建一个玩家生成器,输入名称,输出生成器
func playerGen(name string) func() (string, int) {
	// 血量一直为150
	hp := 150
	// 返回创建的闭包
	return func() (string, int) {
		// 将变量引用到闭包中
		return name, hp
	}
}

func main() {
	// 创建一个玩家生成器
	generator := playerGen("high noon")
	// 返回玩家的名字和血量
	name, hp := generator()
	// 打印值
	fmt.Println(name, hp)
}

多闭包返回

func test01(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 := test01(10)

	fmt.Println(f1(1), f2(2))
	fmt.Println(f1(3), f2(4))
}

 延迟执行语句(defer)

示例1:

func main() {
	fmt.Println("defer begin")

	// 将defer放入延迟调用栈
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)

	fmt.Println("defer end")
}

示例2:

func main() {
	var i int = 0
	defer fmt.Printf("defer i=%d
", i)
	i = 1000
	fmt.Printf("i=%d
", i)
}

defer使用案例

使用defer解锁

在下面的例子中会在函数中并发使用 map ,为防止竞态问题,使用 sync.Mutex 进行加锁,示例:

var (
	// 一个演示用的映射
	valueByKey = make(map[string]int)
	// 保证使用映射时的并发安全的互斥锁
	// map 默认不是并发安全的,准备一个 sync.Mutex 互斥量保护 map 的访问
	valueByKeyGuard sync.Mutex
)
// 根据键读取值
// readValue() 函数给定,从 map 获得值后返回,该函数会在并发环境中使用,需要保证并发安全
func readValue(key string) int {
	valueByKeyGuard.Lock()

	// defer后面的语句不会马上调用,而是延迟到函数结束时调用
	// 该语句不会马上执行,而是等 readValue() 返回时才会被执行。
	defer valueByKeyGuard.Unlock()
	return valueByKey[key]
}

释放文件旬柄

func fileSize(filename string) int64 {

	f, err := os.Open(filename)
	if err != nil {
		return 0
	}
	defer f.Close()

	info, err := f.Stat()
	if err != nil {
		return 0
	}

	size := info.Size()
	
	return size

}
加油,你们是最棒的!
原文地址:https://www.cnblogs.com/Wshile/p/12686511.html