Golang -- 函數

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

函式宣告

func (p myType ) funcName ( a, b int , c string ) ( r , s int ) {    函數體    return 語句}
  • func 關鍵字
  • (p myType) 表明 函數所屬於的類型對象!,即為特定類型定義方法,可以省去不寫,即為普通的函數 (這裡我們主要講解 普通的函數)
  • 函數名
  • 參數 (可以不聲明)
  • 傳回值 (可以不聲明)
  • 函數體

函數調用

我們知道C++的類中有 private,public,friend,可以控制類成員可見度。並且通過命名空間來減少命名衝突。Java也是如此。
在Go語言中 和python一樣,也是採用 package 來對 不同的模組 進行劃分的。

  • 可以直接調用 13 個內建函數(函數全部為小寫名稱)
  • 調用標準包中的函數 (直接匯入標準包 import fmt,通過包名 直接調用
  • 調用一個自訂函數,且和主調函數在同一個包中 (直接調用即可,不用包名首碼)
  • 被調用的函數 由 使用者建立的包提供! (go install 產生 .a 檔案,import 包名,通過包名調用

其中第2中和第4中都是來自外部包,並且函數名稱第一個字母都是大寫字母,所不同的是標準包有Go提供,而使用者自己建立的包由使用者自己建立。

import "pcakageName"packageName.FunctionName(參數)

第三種情況由於被掉函數 和 主調函數在同一個包中,所以直接調用即可,無需匯入包名並且函數首字母可以是小寫字母 (這裡,哪怕兩個兩個函數不在同一個檔案中,只要在同一個包中即可)。

調用標準函數

Golang 提供了 大量的包和實用函數 供使用者使用,這些函數被稱為標準函數。常見的標準包有 fmt, math, os, time bytes 一般包名都是小寫。、
標準包的訊息可以在 Go安裝目錄的 pkg 下面查看,也可以使用godoc 查看。

  • 使用一個函數前首先,匯入包名
  • 通過包名,調用函數

調用自訂函數

通常,一個可執行檔Go程式一般都有一個 main 包,在 main包中必須聲明一個 main 函數

調用 外部包的函數

如果需要調用外部包的函數,那麼需要匯入這個包,才能調用相關函數(首字母必須大寫)。

比如構建 mymath包:
1. 首先建立 mymath.go 源檔案:定義了四個函數 (這個源檔案,必須在目錄 $GOPAHT/src/mymath 下面)

package mymathfunc Add(a, b int) int {    return (a + b)}func Sub(a, b int) int {    return (a - b)}func Mult(a, b int) int {    return (a * b)}func Div(a, b int) int {    if b != 0 {        return float32(a) / float32(b)    } else {        return 0    }}
  1. 調用 go install mypath ,將會在$GOPAHT/src/mymath 下面 編譯這些源檔案,並且安裝到 $GOPATH/src/pkg/(體繫結構名)/下面

  2. 匯入這個包之後就可以直接調用了這些函數了。 系統會在相應的下面找到這個 package,並且找到這些包中的函數。(go buildgo install的區別是什嗎?)

調用內建函數

13個內建函數,這些內建函數,非常有用。
len():可以擷取數組,字串,切片的長度
panic() 可以直接作用於系統底層,用於錯誤處理。

參數傳遞

參數傳遞主要是為了在函數之間,傳遞資料。
Go 語言中,函數參數可以使實值型別,也可以是參考型別。實值型別作為函數參數進行傳遞的時候是一個參數的拷貝。 參考型別是一個地址的拷貝。 大概分為以下幾種類型:

常規傳遞

指標傳遞

數組元素 作為參數

數組名 作為參數 (將會進行數組的整體複製)

package main import (    "fmt")func main() {    var b = [5]int {1, 2, 3, 4, 5}    f4(b)    fmt.Println(b[0])}func f4(a [5]int) {    a[0] += 1    fmt.Println(a[0])  //不會影響原先的數組。因為傳遞數組名是指拷貝}

在使用 數組名 作為參數的時候,實參類型和形參類型必須一致。 比如實參 b的類型是 [5]int,那麼形參的類型也應該是 [5]int。 將形參定義為 []int, [10]int 等類型都是錯誤的,而C語言往往允許這麼做。
Go 語言是型別安全的,[5]int 和 []int、[10]int 用示範不同的類型。 如果你的函數的傳回值類型定義為 float32,那麼如果你在函數中返回一個 int 類型變數也將不會通過。(Go語言是型別安全的)

Slice 作為函數參數

  1. 這是一個地址拷貝,將底層數組的地址賦值給參數的Slice
  2. 對Slice元素的操作即使對底層數組的操作。

函數作為參數傳遞

函數也是一種資料類型,可以將一個函數賦值給一個變數。

func main(){    var a, b int = 3, 4    f := sum    f1(a, b, f)}func f1(a, b int, sum func(int ,int) int) int {    fmt.Println(sum(a, b))}func sum(a, b int) int {    return (a+b)}

傳回值

傳回值: 允許多個傳回值,並且允許定義傳回值變數,這樣return 語句可以更加方便。

func f2(a, b int) (int ,float32){  //多個傳回值 需要一個括弧    return a *b, float32(a) / float32(b)}

同時在調用函數的時候,也可以忽略傳回值。

func main() {    ret, _ := f2(3, 6)  //可以忽略傳回值}func f2(a, b int) (int ,float32){    return a *b, float32(a) / float32(b)}

可以命名傳回值參數,這樣在return 的時候,就可以不用直接寫傳回值了。

func main() {    sum, sub = f3(3, 6)    fmt.Println(sum, sub)}func f3(a, b int) (sum, sub int) { //直接命名了傳回值參數,需要一個括弧    sum = a + b    sub = a - b    return}

變參函數

形式參數的 類型個數 都是可以變化的。
典型的變參函數有: fmt.Printf(), fmt.Scanf() exec.Command() 等

變參函數的聲明

func functionName (variableArgumetName ... dataType) returnValue {...}

(1) 變參的類型是”…類型“,而且變參必須是函數的最後一個參數。如果函數還有其他的參數,比如放在 變參的前面。 func f1(a int ,s string, args ...int) {...}
(2) 不定長 的變參,實際上就是一個切片,可以使用 range 進行遍曆。

package mainimport "fmt"func main() {    f1(1, 2, 3)    f1(4, 5, 6, 7)}func f1(args ...int) {    fmt.Println(args)}輸出為:[1 2 3][4 5 6 7]

變參函數的 傳遞

一個變參函數,如何將這些變參傳遞給另外一個 變參函數呢?
因為實際上變參就是一個切片,所以可以進行全部的傳遞,也可以進行部分的傳遞。

package mainimport "fmt"func main() {    f2(1, 2, 3)    f2(4, 5, 6, 7)}func f1(args ...int) {    fmt.Println(args)}func f2(args ...int) {    f1(args...)    f1(args[2:]...)}

不定長的變參在進行參數傳遞的是偶雖然接受到的是一個 Slice,但是和直接傳遞一個Slice還是有區別的:不定長參數在傳遞一個 Slice的時候,它僅僅是擷取 Slice的一個副本對這個副本進行操作,不會改變原先的Slice的值。

任意類型的 變參函數

當使用者希望傳遞不同類型的參數的時候,就像 fmt.Printf() 可以接受 int string 等各種類型。
此時,應該指定 變參 類型為為 空介面 interface{}

func f1(args... interface{})  //指定變參類型為 interface{}

在Go語言中,interface{} 可以指向任何資料類型,所以可以使用 interface{}定義任意類型的變參。 同時 interface{] 也是型別安全的。 (對所有資料類型的抽象。。。嗎?)

package mainimport (    "fmt")func main() {    f1(2, "go", 8, "language", 'a', false, "A", 3.24)}// 採用 interface {} 作為類型func f1(args ...interface{}) {    var num = make([]int, 0, 6)    var str = make([]string, 0, 6)    var ch = make([]int32, 0, 6)   //字元類型,是int32的哦!    var other = make([]interface{}, 0, 6) //採用 interface{}作為類型    for _, arg := range args {        switch v := arg.(type) {  //這個是什麼用法?        case int:            num = append(num, v)        case string:            str = append(str, v)        case int32:  //這裡 'a' 被統計到了 int32中。            ch = append(ch, v)        default:            other = append(other, v)        }    }    fmt.Println(num)    fmt.Println(str)    fmt.Println(ch)    fmt.Println(other)}輸出為:[2 8][go language A][97][false 3.24]

可以看到: Go 語言是型別安全的。 int 類型和 int32不是同一個類型,但是應該是相容的。 字元 字面值 被當做rune類型(也就是 int32 類型,但是不是 int類型 )

匿名函數

聲明:

func (參數列表)(傳回值){函數體}  //注意沒有函數名,所以稱為匿名函數func (a, b int) int {    return (a + b)}
  1. 可以隨時在代碼裡定義匿名函數,並且將這個匿名函數 賦值 給一個變數。
  2. 可以隨時定義匿名函數,並且 執行這個 匿名函數。(聲明函數的時候,直接執行!)
package mainimport (    "fmt")func main() {    //聲明 並且直接將 匿名函數 賦值 給變數f    f := func(a, b int) int {        return a + b    }    // 對函數類型的變數盡心調用    sum := f(2, 3)      fmt.Println(sum)    // 聲明 並且 直接執行 匿名函數    sum = func(a, b int) int {        return a + b    }(2, 3)    fmt.Println(sum)}

注意: 使用 匿名函數,不能將它作為頂級函數使用,也就是說一定要將它放在其他函數的函數體中。
2. 匿名函數中 可以 直接使用 上級函數中的變數(這也是其一個方便的用處)

函數閉包

closure:

defer 語句

  1. defer 語句 向函數進行註冊。
  2. 在函數退出的時候執行(無論函數是 panic()還是正常退出)
  3. defer 註冊語句遵循 ”先註冊,後執行“的順序
  4. 可以 用 defer 語句進行一些資源清理工作。

Golang 異常恢複機制

golang 的 異常恢複機制,是採用 panic() / recover() 的機制。
這些都是 內建函數。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.