一、函数可赋值给一个变量

示例1:

package main

import "fmt"

func add(a, b int) int {
return a + b
} func main() {
xx := add
fmt.Println(xx(10, 10)) // 20
}

示例2:

package main

import "fmt"

// opFunc为自定义的类型名字,这里它是一个函数,接收两个值,返回一个值
type opFunc func(int, int) int func add(a, b int) int {
return a + b
} // op为变量名字,op_func为自己定义的类型
func operator(op opFunc, a, b int) int {
return op(a, b)
} func main() {
xx := add
result := operator(xx, 10, 10)
fmt.Println(result) // 20
}

示例3:示例2也可以写成如下,示例2中为什么使用type自定义类型?这样可以让函数没那么繁琐,更简洁。

package main

import "fmt"

// opFunc为自定义的类型名字,这里它是一个函数,接收两个值,返回一个值
//type opFunc func(int, int) int func add(a, b int) int {
return a + b
} // op为变量名字,op_func为自己定义的类型
func operator(op func(int, int) int, a, b int) int {
return op(a, b)
} func main() {
xx := add
result := operator(xx, 10, 10)
fmt.Println(result) // 20
} 

二、可变参数

// 0个或多个参数
func sumArgs(args …int) int {
}
// 1个或多个参数
func sumArgs(a int, args …int) int {
}
// 2个或多个参数
func sumArgs(a int, b int, args …int) int {
}

注意:其中args是一个slice,我们可以通过args[index]依次访问所有参数,通过len(args)来判断传递参数的个数。

示例:

package main

import "fmt"

func sumArgs(args ...int) int {
sum := 0
for i := range args {
sum += args[i]
}
return sum
} func main() {
fmt.Println(sumArgs(1, 2, 3, 4, 5)) // 15
}

三、匿名函数

package main

import "fmt"

func add(a, b int) int {
result := func(a1, b1 int) int {
return a1 + b1
}(a, b) // 定义时就调用
return result
} func main() {
fmt.Println(add(10, 10)) // 20
}

或者:

package main

import "fmt"

func add(a, b int) int {
result := func(a1, b1 int) int {
return a1 + b1
}
return result(a, b)
} func main() {
fmt.Println(add(10, 10)) // 20
}

全局匿名函数:

package main

import "fmt"

var (
//Func就是一个全局匿名函数
Func = func(a, b int) int {
return a * b
}
) func main() {
result := Func(10, 10)
fmt.Println(result)
}

四、defer用途

  • 当函数返回时,执行defer语句,因此,可以用来做资源清理;
  • 多个defer语句,按先进后出的方式执行;
  • defer语句中的变量,在defer声明时就决定了。

示例:

package main

import "fmt"

func test(a, b int) {
defer fmt.Println(a)
defer fmt.Println(b)
tmp := a + b
fmt.Println(tmp)
} func main() {
test(10, 20)
} // 输出结果:
// 30
// 20
// 10

在 defer 将语句代码放入到栈时,也会将相关的值拷贝同时入栈:

package main

import "fmt"

func test(a, b int) {
defer fmt.Println(a)
defer fmt.Println(b)
a++
b++
tmp := a + b
fmt.Println(tmp)
} func main() {
test(10, 20)
} // 输出结果:
// 32
// 20
// 10

defer的最主要价值是,当函数执行完毕后,可以及时的释放函数创建的资源(请看如下伪代码):

func test() {
// 关闭文件资源
file = openFile(文件名)
defer file.close()
// 其他代码
} func test() {
// 释放数据库支援
conn = openDatabase()
defer conn.close()
// 其他代码
}

Go:函数、defer的更多相关文章

  1. Go 延迟函数 defer 详解

    Go 延迟函数 defer 详解 Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在实际应用中,很多 gopher 并没有真正搞明白 defer.re ...

  2. Golang入门教程(十三)延迟函数defer详解

    前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在 ...

  3. GO语言延迟函数defer用法分析

    这篇文章主要介绍了GO语言延迟函数defer用法,较为详细的分析了GO语言的特性与具体用法,并给出了一个比较典型的应用实例,具有一定的参考借鉴价值,需要的朋友可以参考下   本文实例讲述了GO语言延迟 ...

  4. Go-延时函数defer

    关于延时调用函数(Deferred Function Calls)      延时调用函数基本语法如下: defer func_name(param-list) {} 当一个函数前有关键字 defer ...

  5. Golang错误处理函数defer、panic、recover、errors.New介绍

    在默认情况下,当发生错误(panic)后,程序就会终止运行 如果发生错误后,可以捕获错误,并通知管理人员(邮件或者短信),程序还可以继续运行,这当然无可厚非 errors.New("错误信息 ...

  6. GO学习笔记:函数defer

    Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句.当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回.特别是当你在进行一些打开资源的操作时,遇 ...

  7. go:defer

    defer:延迟. 假设有调用函数A.被调用函数B,其关系如下: func A(){//调用函数 ... defer B()//被调用函数 ... return//B将延迟到return前执行 } * ...

  8. Golang tips ----- 函数

    1.在函数调用时,Golang没有默认参数值 2.一个函数声明如果没有函数体,表面该函数不是由Golang实现的,这样的声明定义了函数标识符 3.拥有函数名的函数只能在包级语法块中被声明 4.函数值( ...

  9. go基础之--函数和map

    在整理函数之前先整理一下关于指针 指针 普通类型变量存的就是值,也叫值类型.指针类型存的是地址,即指针的值是一个变量的地址.一个指针指示值所保存的位置,不是所有的值都有地址,但是所有的变量都有.使用指 ...

  10. Golang中defer、return、返回值之间执行顺序的坑

    原文链接:https://studygolang.com/articles/4809 Go语言中延迟函数defer充当着 cry...catch 的重任,使用起来也非常简便,然而在实际应用中,很多go ...

随机推荐

  1. BZOJ_1150_[CTSC2007]数据备份Backup_堆+贪心

    BZOJ_1150_[CTSC2007]数据备份Backup_堆+贪心 Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏 ...

  2. SAM入门

    学了两天,会了点皮毛,这里只放代码. P3804 #include<iostream> #include<cstdio> #include<cmath> #incl ...

  3. bzoj3786

    splay维护dfs序 我们发现有移动子树这种操作,树剖是做不了了,又要实现子树加,lct又维护不了了,这时我们用splay维护入栈出栈序来支持这些操作.我们记录每个点的入栈时间和出栈时间,这样一个闭 ...

  4. Java实现二叉树遍历

    参考资料: http://blog.csdn.net/wuwenxiang91322/article/details/12231657 环境: Java: jdk1.8.0_91 import jav ...

  5. 洛谷P3698 [CQOI2017]小Q的棋盘

    传送门 考虑一个贪心,先在根节点周围转一圈,然后再往下走最长链肯定是最优的 然后设最长链的长度为$d$,如果$m\leq d$,那么答案为$m+1$ 否则的话还剩下$m-d+1$步,又得保证能走回来, ...

  6. [Swift]圆周率π

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  7. Hadoop伪分布式模式搭建

    title: Hadoop伪分布式模式搭建 Quitters never win and winners never quit. 运行环境: Ubuntu18.10-server版镜像:ubuntu- ...

  8. javascript实现继承的4种方法,以及它们的优缺点

    1. 原型链继承(有缺陷): 缺陷1:切断了Zi.prototype.constructor与Zi的关系 缺陷2:原型链上的引用类型的数据会被所有实例共享 2. 构造函数继承(有缺陷): 缺陷1:Fu ...

  9. redis在linux的安装和开机启动(二)

    编译 安装 makefile已经存在 执行make 即可 make之后, 自动创建可运行的脚本文件, 不需要再执行 install了. 将脚本文件, 拷贝到指定位置, 就可以了. 手动创建目录, 需要 ...

  10. 2017 Pycharm激活码

    BIG3CLIK6F-eyJsaWNlbnNlSWQiOiJCSUczQ0xJSzZGIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...