zoukankan      html  css  js  c++  java
  • <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
    
    }
    
    加油,你们是最棒的!
  • 相关阅读:
    jquery 父、子页面之间页面元素的获取,方法的调用
    读excle
    dataTable写入数据库(大数据写入)
    经典类和新式类的区别
    重写父类方法
    封装redis
    继承
    私有方法
    优化MyDb

  • 原文地址:https://www.cnblogs.com/Wshile/p/12686511.html
Copyright © 2011-2022 走看看