golang函式使用基礎

机械心發表於2024-05-31

函式

介紹

有其他語言基礎的話就沒啥介紹的,基本語法:

func functionName(形參列別) (返回值列表){
    執行語句
    return 返回值列表
}
例子:
func getSum(n1 int, n2 int) int {
    var res int = n1 +n2
	return res
}

實際就建立不同的資料夾,存放程式檔案。Go的每一個檔案都輸屬於一個包的,go以包的形式來管理檔案和目錄結構。
作用:

  • 區分相同名字的函式與變數符
  • 當專案比較複雜時,便於管理專案
  • 控制函式、變數的訪問範圍,也就是作用域

打包指令:package 包名
引入指令:import "包路徑"

注意事項:

  • 包中的函式與變數如果首字母大寫則是對外公開的,稱為該函式可以匯出,如果小寫則是非公開的
  • 包名通常應該與所處資料夾保持一致,不一致也可以
  • 同一個包下面,不能有相同的函式名
  • main包只能有一個

init函式

每一個原始檔都可以包含一個init函式,該函式在main函式執行之前被Go執行框架呼叫。一般完成初始化工作 。

在一個檔案中如果同時含有全域性變了定義、init函式與main函式,那麼執行流程是:
全域性變數定義->init函式->main函式

當一個檔案引用的包裡面有全域性變數定義與init函式時,先執行包的全域性變數定義與init函式,再執行該檔案的全域性變數定義與init函式,最後執行main函式

匿名函式

如果希望某一個函式只使用一次,可以考慮匿名函式。當然匿名函式也可以實現多次使用。什麼場景下會使用匿名函式呢?也就是閉包。一個最常用的場景就是程式執行出現錯誤的時候,我們要去恢復,一般是透過關鍵字defer,我們要有一個程式邏輯,在某些特定場景下執行的,但是我沒有必要為整個邏輯定義函式,通常這樣就可以使用閉包來做。

  • 使用方式1:在定義時就使用
res1 := func (n1 int, n2 int) int {
    return n1+n2
}(5, 6)//傳入引數
fmt.Printf("res1的值是%d\n", res1)  //結果為11
  • 使用方式2:將匿名函式賦給一個變數,透過變數呼叫函式,可以反覆呼叫(用處感覺不是很大,用處是可以在main()中定義函式)
func main(){
    a = func (n1 int, n2 int) int {  //此時a的資料型別為函式型別
        return n1+n2
    }
    res2 := a(5, 6)  //a是變數,不是函式名
    fmt.Printf("res2的值是%d\n", res2)  //結果為11
    res3 := a(10, 6)  //a是變數,不是函式名
    fmt.Printf("res3的值是%d\n", res3)  //結果為16
}
  • 使用方式3:全域性匿名函式:將匿名函式賦給一個全域性變數,透過變數呼叫函式

閉包

閉包是一個函式和與其相關的引用環境組成的整體。例子:

package main
import (
    "fmt"
)

func AddUpper() func (int) int {
    var n int = 10
    return func(x int) int {
        n = n + x;
        return n
    }
}

func main(){
    f := AddUpper()
    fmt.Println(f(1)) //結果為11
    fmt.Println(f(2)) //結果為13
    fmt.Println(f(3)) //結果為16
    g := AddUpper()
	fmt.Println(g(2)) //結果為12
}
// AddUpper是一個函式,其返回的資料型別是函式型別。
// 返回的匿名函式就是閉包的函式。
// n是引用的環境,構成了一個整體
// 可以理解為閉包是一個類,環境就是成員變數,匿名函式是唯一的一個成員函式。

defer

在函式中需要建立資源(redis,MySQL連結或者檔案、鎖資源),為了在函式執行完畢後及時的釋放資源,Go的設計者提供了defer機制。

package main

import "fmt"

func sum(n1 int, n2 int) int {
    // 當執行到defer時,會將defer後面的語句壓入到一個獨立的棧中,暫時不執行
    // 當函式執行完畢後,再從棧中按照先入後出的方式出棧,並一一執行
    // 在defer將語句入棧時,也會將語句相關的資源與變數複製至棧中,在以下兩個語句中分別就是n1, n2
    defer fmt.Println("ok1 n1=", n1)
    defer fmt.Println("ok2 n1=", n2)
    res := n1 + n2
    fmt.Println("ok3 res=", res)
    return res
}

func main(){
    res := sum(10, 20)、
    fmt.Println("res的值是", res)
}

以上程式碼的輸出結果為:

ok3 res= 30
ok2 n1= 20
ok1 n1= 10
res的值是 30

函式引數的傳遞方式

  1. 值傳遞:基本的資料型別,int,float,string,陣列,結構體,記憶體一般在棧上分配

  2. 引用傳遞:指標,切片,map,管道chan,interface,本質上是地址複製,地址複製效率更高。記憶體通常在堆上分配

func test(n1 *int, n2 *int) int{
    *n1 = *n2 + 5
    return *n1
}

變數作用域

  • 函式內部宣告或者定義的變數叫區域性變數,作用域僅限於函式內部
  • 函式外部宣告或者定義的變數為全域性變數,作用域在整個包都有效,如果首字母大寫,這在整個程式都有效
  • 在if/for中宣告的變數只在這個if/for程式碼塊中有效
  • 就近原則:if/for > 函式內部 > 全域性變數

常用的字串函式

// 統計字串的長度,不用調包,是內建函式
// 返回v中位元組的數量,不是元素的數量,是位元組的數量,一共漢字是三個位元組
func len(v type) int

// 字串遍歷,同時處理有中文的問題
r := []rune(str) //將字串轉為了切片

// 字串轉整數,需要用包strconv, 如果失敗會產生erorr
str1 :="12345"
n err := strconv.Atoi(str1)// n==13245
if err != nil{
    fmt.Println("轉換錯誤:", err)
}else{
    fmt.Println("n的值是:", n)
}

// 整數轉為字串
str2 = strconv.Itoa(123)
fmt.Println("str的值是:", str2)

// 查詢一個字串是否含有某一個子串
strings.Contains(str1, str2)//返回值是bool型別

相關文章