Golang 语言基础之五: function
Golang 语言基础系列:
- Golang 语言基础之一: type, variable, constant
- Golang 语言基础之二: for, ifelse, switch
- Golang 语言基础之三: array, slice
- Golang 语言基础之四: map, range
- Golang 语言基础之五: function
- Golang 语言基础之六: string, pointer
- Golang 语言基础之七: struct, method
- Golang 语言基础之八: interface
- Golang 语言基础之九: error, panic, recover
- Golang 语言基础之十: goroutine, channel
函数
function
是 Golang 的核心,它的定义方式为:
func (variable Type) funcName(var1 Type1, var2 Type2, variabicPara ...TypeX) (ret1 ReturnType1, ret2 ReturnType2) { }
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
1 2 3 4 5 6 7 8 9 10 11 12 13 14
- 使用
func
关键字来定义函数。 - 如果定义时有
(variable Type)
的内容,variable
表示函数所属类型的对象,如果函数体中不需要用到则可以省略。 - 如果定义时有
(variable Type)
的内容,Type
表示函数所属的类型,Type
本身也可以是一个类型的指针,比如struct
User 的指针*User
。 - 函数的名称。
- 函数可以有
0
个或者多个形参,函数第一个形参的名字。 - 函数第一个形参的类型。
- 函数第二个形参的名字。
- 函数第二个形参的类型。
variabicPara ... TypeX
表示可以有可变参数,也就是是零个或者多个同一类型TypeX
的形参,实参传递的时候放入一个名为variabicPara
的slice
对象中。- 函数可以有多个返回值,第一个返回值的名称。(函数可以指定
命名返回值
,也就是说返回值名称在定义函数时确定,并初始化为各自类型的零值。它们在函数内部的使用方式和函数传递的实参是一样的。) - 第一个返回值的类型。
- 第二个返回值的名称。
- 第二个返回值的类型。
- 函数体,在里面可以定义函数的行为。
注意,根据下面 官方文档关于分号的说明,Golang 编译器会在源代码中自动添加分号 ;
,如果 {
单独放在一行的开头,其前面可能会被加入 ;
,造成编译错误。
The formal grammar uses semicolons ";" as terminators in a number of productions. Go programs may omit most of these semicolons using the following two rules:
1. When the input is broken into tokens, a semicolon is automatically inserted into the token stream at the end of a non-blank line if the line's final token is
an identifier
an integer, floating-point, imaginary, rune, or string literal
one of the keywords break, continue, fallthrough, or return
one of the operators and delimiters ++, --, ), ], or }
2. To allow complex statements to occupy a single line, a semicolon may be omitted before a closing ")" or "}".
这个规则适用于其他流程控制语句(for, ifelse, switch, select):
注意:无论任何时候,你都不应该将一个控制结构((if、for、switch或select)的左大括号放在下一行。如果这样做,将会在大括号的前方插入一个分号,这可能导致出现不想要的结果。
而对于 struct
,interface
等类型,gofmt
会自动将左大括号 {
调整到原型声明那一行,所以无需操心。
按照本系列的惯例,还是从实际使用的例子开始:
package main
import "fmt"
// 定义无参数也无返回值的函数
func NoParaNoReturn() {
fmt.Println("I am a function with no parameter and return nothing.")
}
// 定义有参数但是无返回值的函数
func WithParasButNoReturn(intPara1, intPara2 int, strPara string) {
fmt.Println("My parameters are: ", intPara1, intPara2, strPara)
}
// 定义有参数也有返回值的函数
func WithpParasAndReturn(intPara int) (int, int) {
return intPara, intPara * 2
}
//定义有参数也有含命名返回值的函数,return 的时候会默认返回命名返回值 doubledInput
func WithpParasAndNamedReturn(intPara int) (doubledInput int) {
fmt.Println("Initial value of doubledInput of int type is: ", doubledInput)
doubledInput = intPara * 2
return
}
// 定义有参数也有含命名返回值的函数,如果内部声明了和命名返回值同名的局部变量,需要显式返回命名返回值
func WithpNamedReturnAndInnerVar(intPara int) (output int) {
{
var output = 100
output = intPara * 2
return output
}
}
// 定义有 可变参数 的函数
func WithVariabicPara(prefix string, paras ...int) {
tempInt := 0
for _, para := range paras {
tempInt += para
}
fmt.Printf("%s, The sum of paras is: %d\n", prefix, tempInt)
}
// 定义含有闭包或者说匿名函数的函数
func WithClosure(intPara int) func() {
returnFunc := func() {
fmt.Println("Input is: ", intPara)
}
return returnFunc
}
// 定义含有 延时代码 的函数
func DelayCode() {
defer fmt.Println("Defer: I will be executed at last")
defer fmt.Println("Defer: I will be executed at first")
fmt.Println("I will be executed before defer")
}
// 定义含有回调函数的函数
func UseCallback(myFunc func()) {
myFunc()
}
// 定义递归函数
func UseRecursion(num int) int {
if num <= 0 {
return 0
} else if num == 1 || num == 2 {
return 1
} else {
return UseRecursion(num-1) + UseRecursion(num-2)
}
}
// 定义结构体
type User struct {
name string
}
// 定义属于结构体 User 的方法
func (user *User) NameChangedTo(new string) {
user.name = new
}
// 定义属于结构体 User 的另一个方法
func (user *User) GetName() string {
return user.name
}
func main() {
// 调用无参数也无返回值的函数
NoParaNoReturn()
// 调用有参数但是无返回值的函数
WithParasButNoReturn(1, 2, "OK")
// 调用有参数也有返回值的函数
input, output := WithpParasAndReturn(10)
fmt.Printf("The double of %d is: %d\n", input, output)
// 调用有参数也有含命名返回值的函数
fmt.Println("The double of 10 is: ", WithpParasAndNamedReturn(10))
// 调用有参数也有含命名返回值以及同名局部变量的函数
fmt.Println("The double of 10 is: ", WithpNamedReturnAndInnerVar(10))
// 调用 可变参数 的函数
WithVariabicPara("Test", 1, 2, 3)
// 调用递归函数
fmt.Printf("The %d num of Fabinaci is: %d\n", 5, UseRecursion(5))
// 调用含有闭包的函数
WithClosure(100)()
// 调用含有 DelayCode 的函数
DelayCode()
// 调用含有回调函数的函数
UseCallback(DelayCode)
// 调用 struct 的方法
var user User
fmt.Println("user is: ", user)
user.NameChangedTo("new")
fmt.Println("user.name is: ", user.GetName())
}
将上面的代码存入源文件 function.go 并使用 go run function.go
可以看到下面的输入:
I am a function with no parameter and return nothing.
My parameters are: 1 2 OK
The double of 10 is: 20
Initial value of doubledInput of int type is: 0
The double of 10 is: 20
The Double of 10 is: 20
Test, The sum of paras is: 6
The 5 num of Fabinaci is: 5
Input is: 100
I will be executed before defer
Defer: I will be executed at first
Defer: I will be executed at last
I will be executed before defer
Defer: I will be executed at first
Defer: I will be executed at last
user is: {}
user.name is: new
注释中对函数的各种用法的解释很清楚,就不多说了。关于 panic
和 recover
在函数中的用法后面会专门讨论。
参考资料
- The Go Programming Language
- 学习 Go 语言 中文版
- Go in Action 中文版
- The way to Go 中文版
- Go by Example
- Organizing Go code
- Testing Techniques
- Go 语言分享
- Go 学习笔记
- Go 语言简介
- Tony Bai 的博客
声明: 本文采用 BY-NC-SA 协议进行授权. 转载请注明转自: Golang 语言基础之五: function
有疑问加站长微信联系(非本文作者)
