函数声明
函数构成代码执行的逻辑结构。在
Go
语言中,函数的基本组成为:关键字
func
、函数名、
参数列表、返回值、函数体和返回语句。
package mymath import "errors" func Add(a int, b int) (ret int, err error) { if a < 0 || b < 0 { // 假设这个函数只支持两个非负数字的加法 err= errors.New("Should be non-negative numbers!") return } return a + b, nil // 支持多重返回值 }
函数调用
先导包,包必须在gopath/src中
Go
语言中函数名字的大小写不仅仅是风格,更直接体现了该函数的可见性,这一点尤其需
要注意。
小写字母开头的函数只在本包内可见,大写字母开头的函数才
能被其他包使用。
这个规则也适用于类型和变量的可见性。
不定参数
1不定参数类型
不定参数是指函数传入的参数个数为不定数量。为了做到这点,首先需要将函数定义为接受
不定参数类型:
func
myfunc(args …
int
) {
for
_, arg :=
range
args {
fmt.Println(arg)
}
}
形如
…type
格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数。
如果你希望传任意类型,可以指定类型为
interface{}
package main import "fmt" func MyPrintf(args ...interface{}) { for _, arg := range args { switch arg.(type) { case int: fmt.Println(arg, "is an int value.") case string: fmt.Println(arg, "is a string value.") case int64: fmt.Println(arg, "is an int64 value.") default: fmt.Println(arg, "is an unknown type.") } } } func main() { var v1 int = 1 var v2 int64 = 234 var v3 string = "hello" var v4 float32 = 1.234 MyPrintf(v1, v2, v3, v4) } 该程序的输出结果为: 1 is an int value. 234 is an int64 value. hello is a string value. 1.234 is an unknown type.
多返回值
比如
File.Read()
函
数就可以同时返回读取的字节数和错误信息。如果读取文件成功,则返回值中的
n
为读取的字节
数,
err
为
nil
,否则
err
为具体的出错信息:
func
(file *File) Read(b []
byte
) (n
int
, err Error)
同样,从上面的方法原型可以看到,我们还可以给返回值命名,就像函数的输入参数一样。
返回值被命名之后,它们的值在函数开始的时候被自动初始化为空。在函数中执行不带任何参数
的
return
语句时,会返回对应的返回值变量的值。
匿名函数与闭包
在
Go
里面,函数可以像普通变量一样被传递或使用,这与
C
语言的回调函数比较类似。不同
的是,
Go
语言支持随时在代码里定义匿名函数。
匿名函数由一个不带函数名的函数声明和函数体组成,如下所示:
func
(a, b
int
, z
float64
)
bool
{
return
a*b <
int
(z)
}
匿名函数可以直接赋值给一个变量或者直接执行
:
闭包
Go
的匿名函数是一个闭包,下面我们先来了解一下闭包的概念、价值和应用场景。
基本概念
闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者
任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含
在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环
境(作用域)。
闭
包的价
值
闭包的价值在于可以作为函数对象或者匿名函数,对于类型系统而言,这意味着不仅要表示
数据还要表示代码。支持闭包的多数语言都将函数作为第一级对象,就是说这些函数可以存储到
变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。
Go
语言中的闭包
Go
语言中的闭包同样也会引用到函数外的变量。闭包的实现确保只要闭包还被使用,那么
被闭包引用的变量会一直存在
package main import ( "fmt" ) func main() { var j int = 5 a := func()(func()) { var i int = 10 return func() { fmt.Printf("i, j: %d, %d\n", i, j) } }() a() j *= 2 a() }
错误处理
Go
语言引入了一个关于错误处理的标准模式,即
error
接口,该接口的定义如下:
type
error
interface
{
Error()
string
}
defer
延迟到return之前执行
另外,一个函数中可以存在多个
defer
语句,因此需要注意的是,
defer
语句的调用是遵照
先进后出的原则,即最后一个
defer
语句将最先被执行。
panic()
和
recover()
在一个函数执行过程中调用
panic()
函数时,正常的函数执行流程将立即终止,但函数中
之前使用
defer
关键字延迟执行的语句将正常展开执行,之后该函数将返回到调用函数,并导致
逐层向上执行
panic
流程,直至所属的
goroutine
中所有正在执行的函数被终止。错误信息将被报
告,包括在调用
panic()
函数时传入的参数,这个过程称为错误处理流程。
recover()
函数用于终止错误处理流程。一般情况下,
recover()
应该在一个使用
defer
关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的
goroutine
中明确调用恢复
过程(使用
recover
关键字),会导致该
goroutine
所属的进程打印异常信息后直接退出
转载于:https://www.cnblogs.com/tomhuang/p/11535879.html