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

示例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. USACO 刷题有感

    最近每天都尽量保持着每天一道USACO的题目,呵呵,一开始都是满简单的,一看题目基本上思路就哗啦啦地出来了,只不过代码实现有点麻烦,花了一些时间去调试,总体感觉还不错,但是越往后做,应该就很难保持一天 ...

  2. BZOJ_2160_拉拉队排练_manacher

    BZOJ_2160_拉拉队排练_manacher Description 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了.拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛 ...

  3. flask g对象

    g对象  一次请求中使用 下面用redirect重定向,不是同一次请求了 g:global 1. g对象是专门用来保存用户的数据的. 2. g对象在一次请求中的所有的代码的地方,都是可以使用的. 使用 ...

  4. mybatis中各种数据的映射类型

    Mybatis对应的java和数据库的数据类型,最后有图片 Mybatis                                  java                          ...

  5. UVaLive 6680 Join the Conversation (DP)

    题意:给出n条发言,让你求最大的交流长度并输出标记顺序. 析:这个题要知道的是,前面的人是不能at后面的人,只能由后面的人at前面的,那就简单了,我们只要更新每一层的最大值就好,并不会影响到其他层. ...

  6. poj 2409 Let it Bead【polya定理+burnside引理】

    两种置换 旋转:有n种,分别是旋转1个2个--n个,旋转i的循环节数位gcd(i,n) 翻转:分奇偶,对于奇数个,只有一个珠子对一条边的中点,循环节数为n/2+1:对于偶数个,有珠子对珠子和边对边,循 ...

  7. 全面学习ORACLE Scheduler特性(11)使用Job Classes

    六.使用Job Classes Job Classes 相当于创建了一个job组,DBA可以将那些具有相同特性的job,统统放到相同的Job Classes中,然后通过对Job Class应用ORAC ...

  8. C# 堆VS栈 值类型VS引用类型

    最近博客园上连续出现了几篇关于堆VS栈 值类型VS引用类型的文章. 一个是关于C# 堆VS栈的,深入浅出,动图清晰明了,链接如下 C#堆栈对比(Part One) C#堆栈对比(Part Two) C ...

  9. linux下jdk与tomcat的安装与配置

    Linux中jdk与tomcat的安装与配置 1.搭建环境: (1)Linux环境:CentOS6.1 (2)jdk-1.8 (3)tomcat-9.0 2.在Linux系统上创建目录 在usr/lo ...

  10. VC++常见错误原因解析--error LNK2019: 无法解析的外部符号 "public: void __thiscall

    根据个人遇到这个错误时的记录,原因可以分为一下几种: 原因一: 只是在.h里面声明了某个方法, 没有在cpp里面实现 . 具体讲,有时候在头文件中声明了需要的方法,确实忘记了在源文件中实现: 有时候在 ...