四时宝库

程序员的知识宝库

Go语言极简教程 - 第六篇 函数(go语言技巧)

Go语言既不像Java和C#那样是面向对象的编程语言,也不像Lisp和Haskell那样是纯函数式的编程语言。在Go语言中,函数是“一等公民”。

函数声明

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

函数的定义以func关键字开头,函数名与func关键字以空格分隔,函数名规范需符合Go语言中的标识符规范。函数可以有零个或多个参数,也可以有零个或多个返回值。

示例

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

函数特点

多值返回

函数允许返回多个值,多个返回值时需要将返回类型列表用()括起来。

不定参数

函数支持不定数目的形式参数,不定参数声明使用...type格式。在函数体内部,不定参数是一个slice类型,所有对slice类型的操作同样也适用于不定参数。

func printList(arr ...int){
 for _, value := range arr {
 fmt.Println(value)
 }
}

Go函数对不定参数有一定的约束:

  • 函数只能有一个不定参数。
  • 不定参数必须是函数形参列表的最后一个。
  • 不定参数作为另一个含有不定参数的函数的实参数传递时需要通过“...”来解参传递

不支持参数默认值

Go语言为了追求显式的表达,避免隐含,因此不支持参数默认值。

不支持函数重载

其它语言中,例如Java、C#都支持方法重载,即同一个类中有多个同名方法,但参数类型或参数数量不同。Go语言不支持同一个作用域范围内多个函数名称相同的情况,因此也不支持 函数重载。

匿名函数

上述的函数都是具名函数,与具名函数相对应的叫匿名函数。Go语言同样支持匿名函数,匿名函数没有函数名称,可以在其它函数体内定义。

匿名函数用得最频繁的应该是在defer延迟执行语句,示例如下:

func Inc() (value int){
 defer func(){value++}
 return 9
}

匿名函数还可以做为函数的返回值,示例如下:

package main
import "fmt"
func main () {
 // 调用高阶函数add,完成3+2的计算
 sum:=add(3)(2) 
 fmt.Printf("3+2=%d\n",sum)
}
// add函数返回一个匿名函数
func add(a int) func(int) int{
 return func(b int) int{
 return a+b
 }
}

匿名函数还可以赋值给一个变量,示例如下:

package main
import "fmt"
func main () {
 // 可以像调用普通具名函数那样调用函数变量
 result:=subtract(3,2)
 fmt.Printf("3-2=%d\n",result)
}
// 声明一个函数类型变量,并用匿名函数初始化
var subtract = func(a,b int) int {
 return a-b
}

函数类型

Go语言中,可以将函数作为变量的数据类型,也可以将函数作为参数的数据类型,还可以将函数作为函数返回值的数据类型。

定义一个函数类型:

type Subtracter func(a,b int ) int

定义函数类型的变量

func do() {
 var subtract Subtracter // 定义一个函数类型的变量subtract
 // 初始化subtract变量
 subtract= func(a, b int) int {
 return a-b
 }
 // 调用subtract函数类型的变量
 result:=subtract(3,2)
 fmt.Printf("3-2=%d\n",result)
}

将函数作为参数类型

func do() {
 var subtract Subtracter
 subtract= func(a, b int) int {
 return a-b
 }
 // 将函数类型的变量传递为doSubtract函数
 result:=doSubtract(subtract)
 fmt.Printf("3-2=%d\n",result)
}
// 将函数类型作为形参
func doSubtract(fun Subtracter) int {
 return fun(3,2)
}

将函数作为返回值类型

func do() {
 subtract:=getSubtract()
 result:=doSubtract(subtract)
 fmt.Printf("3-2=%d\n",result)
}
// 将函数类型作为返回值
func getSubtract() Subtracter{
 return func(a, b int) int {
 return 3-2
 }
}

函数闭包

函数体内声明的局部变量作用域仅限于该函数体内,函数体外部无法访问。另外,函数体内声明的局部变量生命周期会随函数的返回而结束(不考虑局部变量被作为引用返回的情形)。但是,通过闭包不仅可以让局部变量被函数体外部访问,还能延长局部变量的生命周期。

func main(){
 w,r:=func1()
 w(13) // 修改value值
 result:=r() // 读取value值
 fmt.Printf("result:%d\n",result)
}
//声明两个函数类型writer,reader
type (
 writer func(int)
 reader func()int)
//定义函数func1,返回writer,reader函数类型
func func1() (writer,reader){
 var value int //局部变量的生命周期被延长,不再随func1调用结束而结束
 w:=func(a int){ //返回一个可以修改value值的函数
 value=a
 }
 r:=func()int{ //返回一个可以读取value值的函数
 return value
 }
 return w,r
}

闭包的底层实现

在编译器层面,Go语言编译器生成一个struct,将value变量以函数writer、reader指针作为struct的成员字段,并返回给func1的调用者。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接