在任何编程语言中,都必须编写优秀的代码。 优秀的代码意味着高效运行和可读性强,大部分人(尤其是程序员或开发人员)都容易理解该代码。通过函数将大部分代码拆分为较小的代码块。
Function in Go
函数是一段代码,用于执行可以重用的特定任务。
//func receiver functionName(parameters types) return type
func (receiver)funcName(params) returnValues {
//code
}
使用函数
//declare a function called greet
func greet() {
fmt.Println("Hello!")
}
func main() {
greet() //prints "Hello!"
}
我们在main函数中调用一个简单的函数greet()。
package main
import (
"fmt"
)
//With one parameter with return value type string
func greet(s string) string {
return fmt.Sprint("Hello ", s, "!")
}
//With two parameters with return value type boolean
func search(word string, keyword string) bool {
return strings.Contains(word, keyword)
}
//With variadic parameter with two return values type int
func countAvg(xi ...int) (int, int) {
total := 0
//calculate sum of ints
for _, v := range xi {
total += v
}
//calculate average of int
avg := total / len(xi)
return total, avg
}
func main() {
greetings := greet("John Doe")
sum, avg := countAvg(1, 2, 3, 4, 5, 6)
fmt.Println(greetings)
fmt.Println("sum: ", sum, " average: ", avg)
fmt.Println(search("Go is really awesome", "is"))
}
countAvg的参数称为可变参数。 可变参数是可以被多个值动态使用的参数。 可变参数必须放在函数参数声明的最后部分。
//example
func foo(s string, xi ...int) {
//code
}
// 这是错误的示范,程序会抛出错误
func foo(xi ...int, s string) {
//code
}
Function with receiver
声明函数时,也可以在function中声明接收者(receiver)。如果我们使用struct,那么receiver真的很有用。
在编写函数之前,让我们创建一个称为person的简单struct。
type person struct {
name string
}
然后,创建一个名为greet()的函数,其receiver类型的称为person。
func (p person) greet() {
fmt.Println("Hello, my name is", p.name, "!")
}
要使用此函数,必须先实例化该结构,然后调用该函数。
func main() {
p := person{name: "Firstname"} //instantiate the struct
p.greet() //call greet() from instantiated struct called p
}
匿名Function
匿名函数是没有名称的函数。
func() {
//code
}
// using IIFE (Immediately-invoked Function Expression) style, we can declare a function that executes directly
func() {
//code
}() // 使用这种语法会马上调用函数
匿名函数的使用:
func() {
//calculates sum
xi := []int{1,2,3,4,5,6}
total := 0
for _, v := range xi {
total += v
}
fmt.Println("The sum is: ",total) // The sum is: 21
}()
Go里面的头等公民
Go中的头等公民原则也适用,但很少使用。 头等公民是指函数可用作函数中的参数或返回值。
func main() {
//declare a function that stored inside variable called cb
cb := func(xi ...int) int {
total := 0
for _, v := range xi {
total += v
}
return total
}
//declare a slice of int
data := []int{1, 2, 3, 4, 5, 6}
//call foo() function with arguments:
//1. cb means callback function
//2. data... means retrieve all items from slice called "data"
result := foo(cb, data...)
fmt.Println("the result: ", result) // the result: 21
}
func foo(callback func(...int) int, xi ...int) int {
return callback(xi...)
}
闭包
闭包是一个持有外部环境变量的函数。
//declare a function that returns a function with return value int
func increment() func() int {
i := 0 //forms a closure
return func() int {
i++ //access variable "i" from outside this function body
return i
}
}
func main() {
myInt := increment()
fmt.Println(myInt())
fmt.Println(myInt())
fmt.Println(myInt())
myInt2 := increment() //this function call resets "i" value
fmt.Println(myInt2())
}
递归
递归是一个能够自行执行功能的函数。 像计算阶乘这类问题,可以使用递归巧妙解决。
func factorial(n int) int {
if n == 0 || n == 1 {
return 1
} else {
return n * factorial(n-1)
}
}
func main() {
result := factorial(5)
fmt.Println("The result: ", result) // The result: 120
}
// 5!的计算方法:
// 5! = 5 * 4 * 3 * 2 * 1
// 使用factorial函数:
// 5! = factorial(5)
// = 5 * factorial(4)
// = 5 * 4 * factorial(3)
// = 5 * 4 * 3 * factorial(2)
// = 5 * 4 * 3 * 2 * factorial(1)
// = 5 * 4 * 3 * 2 * 1 * factorial(0)
// = 5 * 4 * 3 * 2 * 1 * 1
// = 120
defer, panic and recover
在某些情况下,需要在某个时间执行函数。例如,必须在某些函数完成后执行functionA()。 基于这种情况,defer语句确实很有用。 defer是在函数完成后才执行。
//(x,y int) is shorthand version of (x int, y int)
func calculate(x, y int) int {
return x + y
}
func main() {
defer fmt.Println("First")
fmt.Println(calculate(4, 5)) // 在fmt.Println(calculate(4,5))完成后执行延迟函数fmt.Println("First")。
}
// output
// 9
// First
Go中有许多错误处理机制,示例之一使用panic函数。 如果发生错误,则执行紧急处理并停止程序。
func divide(x, y int) int {
if y == 0 { // 如果y ==0 程序发生panic
panic("cannot divide by 0")
} else {
return x / y
}
}
func main() {
fmt.Println(divide(24, 0))
fmt.Println("Hello") //这句不会运行
}
// output
// panic: cannot divide by 0
尽管程序出现panic,但defer仍然会执行。
func divide(x, y int) int {
if y == 0 {
panic("cannot divide by 0")
} else {
return x / y
}
}
func main() {
defer fmt.Println("Hello") //this is executed because this function is deferred
fmt.Println(divide(24, 0))
}
// output
// Hello
// panic: cannot divide by 0
要恢复出现panic的程序,可以在defer函数中使用recover函数。 如果在非defer函数中使用,recover函数将变得毫无作用,因为程序处于panic状态,defer函数仍将执行。
func divide(x, y int) int {
if y == 0 {
panic("cannot divide by 0")
} else {
return x / y
}
}
func main() {
//declare an anonymous func to recover from panic
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered!")
}
}()
fmt.Println(divide(24, 0))
}
// output
// Recovered!
divide()函数处于panic状态,但defer函数仍然执行。 执行匿名函数以从panic中恢复,最后停止程序执行。
资料来源
以下是一些有用的资源,可进一步了解Go编程语言
- Function
- Function Declaration
- Function Literal
- Closure
- defer,panic and recover
我希望本文对帮助学习Go编程语言有所帮助。 如果您有任何想法或反馈,可以在下面的评论留言。