函數 - Go 語言學習筆記

函數是什麼?

函數是一塊執行特定任務的代碼,是構成代碼執行的邏輯結構。編程

在Go語言中,函數的基本組成是:關鍵字func、函數名、參數列表、返回值列表、函數體和返回語句。bash

函數的聲明

Go語言函數聲明語法以下:閉包

func function_name( [parameter list] ) [return_types] {
    函數體(具體實現的功能)
}
複製代碼

函數語法解析:函數

  • func:函數由 func 開始聲明
  • function_name:函數名稱,函數名和參數列表一塊兒構成了函數簽名
  • parameter list:參數列表,參數就像一個佔位符,當函數被調用時,你能夠將值傳遞給參數,這個值被稱爲實際參數。參數列表指定的是參數類型、順序、及參數個數。參數是可選的,也就是說函數也能夠不包含參數。
  • return_types:返回類型,函數返回一列值。return_types 是該列值的數據類型。有些功能不須要返回值,這種狀況下 return_types 不是必須的。
  • 函數體:函數定義的代碼集合。

實例:ui

func calculateBill(price int, no int) int {  
    var totalPrice = price * no     // 商品總價 = 商品單價 * 數量
    return totalPrice               // 返回總價
}
/* 上述函數有兩個整型的輸入 price 和 no,返回值 totalPrice 爲 price 和 no 的乘積,也是整數類型。*/
複製代碼

若是有連續若干個參數,它們的類型一致,那麼咱們無須一一羅列,只需在最後一個參數後添加該類型。 例如:spa

func calculateBill(price, no int) int {
    var totalPrice = price * no
    return totalPrice
}
複製代碼

函數調用

當建立函數時,你定義了函數須要作什麼,經過調用該函數來執行指定任務。指針

調用函數,向函數傳遞參數,並返回值,例如:code

package main
func calculateBill(price, no int) int {
    var totalPrice = price * no
    return totalPrice
}

func main() {
    var ret int
    ret = calculateBill(10, 5)
}
複製代碼

函數參數

函數使用的參數稱爲函數的形參,形參就像定義在函數體內的局部變量。 調用函數,能夠經過兩種方式來傳遞參數:對象

1. 值傳遞

值傳遞是指在調用函數時將實際參數複製一份傳遞到函數中,這樣在函數中若是對參數進行修改,將不會影響到實際參數。

默認狀況下,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;
}
```
如下代碼執行結果爲:

交換前 a 的值爲 : 100<br />
交換前 b 的值爲 : 200<br />

交換後 a 的值 : 100<br />
交換後 b 的值 : 200
複製代碼

2. 引用傳遞

引用傳遞是指在調用函數時將實際參數的地址傳遞到函數中,那麼在函數中對參數所進行的修改,將影響到實際參數。

引用傳遞指針參數傳遞到函數內,例如:
```
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
}
```

以上代碼執行結果爲:

交換前,a 的值 : 100<br />
交換前,b 的值 : 200<br />

交換後,a 的值 : 200<br />
交換後,b 的值 : 100
複製代碼

多返回值

Go語言支持一個函數能夠有多個返回值,若是一個函數有多個返回值,那麼這些返回值必須用 ( 和 ) 括起來。 例如,定義個以矩形的長和寬爲輸入參數,計算並返回矩形面積和周長的函數 rectProps。get

  • 面積 = 長 * 寬
  • 周長 = 2 * ( 長 + 寬 )
package main

import (  
    "fmt"
)

func rectProps(length, width float64)(float64, float64) {  
    var area = length * width
    var perimeter = (length + width) * 2
    return area, perimeter
}

func main() {  
    area, perimeter := rectProps(10.8, 5.6)
    fmt.Printf("Area: %f Perimeter: %f", area, perimeter) 
}
複製代碼

以上實例執行結果爲:Area: 60.480000 Perimeter: 32.800000

命名返回值

從函數中能夠返回一個命名值。一旦命名了返回值,能夠認爲這些值在函數第一行就被聲明爲變量了。

例如:

func rectProps(length, width float64)(area, perimeter float64) {  
    area = length * width
    perimeter = (length + width) * 2
    return // 不須要明確指定返回值,默認返回 area, perimeter 的值
}
複製代碼

注意, 函數中的 return 語句沒有顯式返回任何值。因爲 area 和 perimeter 在函數聲明中指定爲返回值, 所以當遇到 return 語句時, 它們將自動從函數返回。

空白符

_ 在 Go 中被用做空白符,能夠用做表示任何類型的任何值。

函數rectProps計算的是面積和周長。假使咱們只須要計算面積,而並不關心周長的計算結果,這時可使用空白符 _ 替換周長。 例如:

package main
import (  
    "fmt"
)

func rectProps(length, width float64) (float64, float64) {  
    var area = length * width
    var perimeter = (length + width) * 2
    return area, perimeter
}

func main() {  
    area, _ := rectProps(10.8, 5.6) // 返回值周長被丟棄
    fmt.Printf("Area %f ", area)
}
複製代碼

在程序 area, _ := rectProps(10.8, 5.6) 的這一行,空白符 _ 用來跳過不要的計算結果。

函數用法

1. 函數做爲另一個函數的實參

函數定義後可做爲另一個函數的實參數傳入 例如:

package main
import (
    "fmt"
    "math"
)

func main(){
    // 聲明函數變量
    getSquareRoot := func(x float64) float64 {
        return math.Sqrt(x)
    }
    
    // 使用函數
    fmt.Println(getSquareRoot(9))
}
複製代碼

2. 閉包

閉包是匿名函數,可在動態編程中使用。
Go 語言支持匿名函數,可做爲閉包。匿名函數是一個"內聯"語句或表達式。匿名函數的優越性在於能夠直接使用函數內的變量,沒必要聲明。 示例:

package main
import "fmt"

func getSequence() func() int {
    i:=0
    return func() int {
        i+=1
        return i  
    }
}

func main(){
    /* nextNumber 爲一個函數,函數 i 爲 0 */
    nextNumber := getSequence()  
    
    /* 調用 nextNumber 函數,i 變量自增 1 並返回 */
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
    
    /* 建立新的函數 nextNumber1,並查看結果 */
    nextNumber1 := getSequence()  
    fmt.Println(nextNumber1())
    fmt.Println(nextNumber1())
}
複製代碼

函數 getSequence() ,返回另一個函數(匿名函數),該函數的目的是在閉包中遞增 i 變量。

3.方法

方法就是一個包含了接受者的函數,接受者能夠是命名類型或者結構體類型的一個值或者是一個指針。全部給定類型的方法屬於該類型的方法集。 語法格式以下:

func (variable_name variable_data_type) function_name() [return_type]{
    /* 函數體*/
}
複製代碼

下面定義一個結構體類型和該類型的一個方法:

package main
import (
    "fmt"  
)

/* 定義結構體 */
type Circle struct {
    radius float64
}

func main() {
    var c1 Circle
    c1.radius = 10.00
    fmt.Println("圓的面積 = ", c1.getArea())
}

//該 method 屬於 Circle 類型對象中的方法
func (c Circle) getArea() float64 {
    //c.radius 即爲 Circle 類型對象中的屬性
    return 3.14 * c.radius * c.radius
}
複製代碼

以上代碼執行結果爲: 的面積 = 314

相關文章
相關標籤/搜索