golang函數使用基礎
函數
介紹
有其他語言基礎的話就沒啥介紹的,基本語法:
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
函數參數的傳遞方式
-
值傳遞:基本的數據類型,int,float,string,數組,結構體,內存一般在棧上分配
-
引用傳遞:指針,切片,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類型

浙公網安備 33010602011771號