目錄
定義一個函數
函數聲明需要指定
- 函數的名稱
- 形參列表
- 返回值列表
函數名和形參列表一起構成函數簽名。格式:
func function_name([parameter list]) [return_types] {
函數體
}
示例:
/* 函數返回兩個數的最大值 */
func max(num1, num2 int) int {
/* 聲明局部變量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
形參列表
值傳遞
值傳遞是指在調用函數時將實際參數複製一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數。默認情況下,Go 語言使用的是值傳遞,即在調用過程中不會影響到實際參數。
示例:
package main
import "fmt"
func main() {
/* 定義局部變量 */
var a int = 100
var b int = 200
fmt.Printf("交換前 a 的值爲 : %d\n", a)
fmt.Printf("交換前 b 的值爲 : %d\n", b)
/* 通過調用函數來交換值 */
swap(a, b)
fmt.Printf("交換後 a 的值 : %d\n", a)
fmt.Printf("交換後 b 的值 : %d\n", b)
}
/* 定義相互交換值的函數 */
func swap(x, y int) int {
var temp int
temp = x /* 保存 x 的值 */
x = y /* 將 y 值賦給 x */
y = temp /* 將 temp 值賦給 y*/
return temp;
}
引用傳遞
引用傳遞是指在調用函數時將實際參數的地址傳遞到函數中,那麼在函數中對參數所進行的修改,將影響到實際參數。類似於 C 語言函數定義中的指針類型形參。
引用傳遞方式,將指針參數傳遞到函數內,以下是交換函數 swap() 使用了引用傳遞:
package main
import "fmt"
func main() {
/* 定義局部變量 */
var a int = 100
var b int= 200
fmt.Printf("交換前,a 的值 : %d\n", a)
fmt.Printf("交換前,b 的值 : %d\n", b)
/* 調用 swap() 函數
* &a 指向 a 指針,a 變量的地址
* &b 指向 b 指針,b 變量的地址
*/
swap(&a, &b)
fmt.Printf("交換後,a 的值 : %d\n", a)
fmt.Printf("交換後,b 的值 : %d\n", b)
}
func swap(x *int, y *int) {
var temp int
temp = *x /* 保存 x 地址上的值 */
*x = *y /* 將 y 值賦給 x */
*y = temp /* 將 temp 值賦給 y */
}
返回值
Go 函數可以返回多個值,例如:
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
}
回調函數
回調函數,即一個函數作爲另外一個函數的實參。所以,在傳遞一個函數之前,首先需要創建一個函數變量。這與 C 語言中的函數指針(指向函數的指針)類似。
package main
import (
"fmt"
"math"
)
func main(){
/* 聲明函數變量 */
getSquareRoot := func(x float64) float64 {
return math.Sqrt(x)
}
/* 使用函數 */
fmt.Println(getSquareRoot(9))
}
再一個示例:
package main
import "fmt"
// 聲明一個函數類型
type cb func(int) int
func main() {
testCallBack(1, callBack)
testCallBack(2, func(x int) int {
fmt.Printf("我是回調,x:%d\n", x)
return x
})
}
func testCallBack(x int, f cb) {
f(x)
}
func callBack(x int) int {
fmt.Printf("我是回調,x:%d\n", x)
return x
}
閉包(Closure)函數
閉包(Closure):如果內層函數引用了外層函數的局部變量,並且在外層函數中 return 內層函數,這種關係就稱之爲閉包。
可見,閉包的特點是發生在函數嵌套的基礎上實現。外層函數返回的內層函數還引用了外層函數的局部變量,所以要想正確的使用閉包,那麼就要確保這個被內層函數引用的局部變量是不變的。Python 中使用閉包函數來實現了裝飾器機制。
Golang 支持匿名函數,可用於實現閉包。匿名函數是一個表達式嗎,其優越性在於可以直接使用函數內的變量,而不必聲明函數名。以下示例中,定義了函數 getSequence() 並返回了另外一個函數。getSequence() 函數的目的是在閉包中遞增 i 變量。
package main
import "fmt"
/**
* getSequence 函數作爲外存函數,其返回值爲匿名函數 func() int,
* 匿名函數 func() int 作爲內層函數,直接使用了外層函數的局部變量 i,
* 如此形成了一個閉包。
*/
func getSequence() func() int {
i := 0
return func() int {
i += 1
return i
}
}
func main(){
/* 定義一個函數變量 nextNumber,當前 i 變量爲 0 */
nextNumber := getSequence()
/* 傳入函數作爲實參,i 變量自增 1 並返回 */
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
/* 創建新的函數 nextNumber1,並查看結果 */
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
}
結果:
1
2
3
1
2
3
方法函數
在常規的面向對象編程語言(OOP)中,比如 Python。函數(Function)和方法(Method)是屬於兩個不同的術語:在類中定義的稱爲成員方法,不在類中定義的稱爲獨立函數。
我們知道 Golang 不是一種 OOP 類型編程語言,但 Golang 也同時提供了方法和函數的概念:一個方法就是一個包含了接受者的函數,接受者可以是命名類型或者結構體類型的一個值或一個指針。
所有給定類型的方法屬於該類型的方法集。語法格式如下:
func (variable_name variable_data_type) function_name() [return_type]{
/* 函數體*/
}
示例:
package main
import "fmt"
/* 定義結構體 */
type Circle struct {
radius float64
}
//該 method 屬於 Circle 類型對象中的方法
func (c Circle) getArea() float64 {
// c.radius 即爲 Circle 類型對象中的屬性
return 3.14 * c.radius * c.radius
}
func main() {
var c1 Circle
c1.radius = 10.00
fmt.Println("圓的面積 = ", c1.getArea())
}
從上述例子可見,方法 getArea 就像是變量 c1 的成員屬性一般,類似於 Python 類對象的一個成員方法。
遞歸函數
遞歸,就是在運行的過程中調用自己。Golang 支持遞歸調用,但我們在使用遞歸時,需要合理設置退出條件,否則遞歸將陷入無限循環中。
格式:
func recursion() {
recursion() /* 函數調用自身 */
}
func main() {
recursion()
}
遞歸函數對於解決數學上的問題是非常有用的,就像計算階乘,生成斐波那契數列等。
- 階乘:
package main
import "fmt"
func Factorial(n uint64) (result uint64) {
if (n > 0) {
result = n * Factorial(n-1)
return result
}
return 1
}
func main() {
var i int = 15
fmt.Printf("%d 的階乘是 %d\n", i, Factorial(uint64(i)))
}
- 斐波那契數列:
package main
import "fmt"
func fibonacci(n int) int {
if n < 2 {
return n
}
return fibonacci(n-2) + fibonacci(n-1)
}
func main() {
var i int
for i = 0; i < 10; i++ {
fmt.Printf("%d\t", fibonacci(i))
}
}