函數
1. 定義格式
- 基本組成:關鍵字func、函數名、參數列表、返回值、函數體和返回語句
- 只有一個返回值且不聲明變量,可以省略括號
2. 自定義函數
1. 無參無返回值
func TestFunc() {
a := 2
fmt.Println("This is a test func, a is ", a)
}
func main() {
TestFunc() //無參無返回值函數調用
}
2. 有參無返回值
1). 普通參數列表
- 定義函數時,在函數名後邊 ( ) 定義的參數叫形參
- 調用函數傳遞的參數叫實參
- 參數傳遞,只能由實參傳遞給形參
func TestFunc1(a, b int) { fmt.Println("a = ", a) fmt.Println("b = ", b) } func main() { TestFunc1(0, 12) }
2). 不定參數列表
-
不定參數類型
-
指函數傳入的參數個數爲不定數量
-
需要將函數定義爲接受不定參數類型
-
傳遞的實參可以是0或多個
func TestFunc(args ...int){ fmt.Println(len(args)) }
-
-
不定參數的傳遞
func func1(tmp ...int) { for _, data := range tmp{ fmt.Printin(data) } } func func2(tmp ...int) { for _, data := range tmp{ fmt.Printin(data) } } func Test(args ... int) { // 全部參數傳遞給Test func1(args...) // 只把後兩個參數傳遞 // func2(args[2:]...) } func main() { Test(1, 2, 3, 4) }
3. 無參有返回值
- 有返回值的函數,必須有明確的終止語句
- 官方建議,最好命名返回值
- 1). 一個返回值
func Test() int{ return 123 } // 給返回值命名 func TestName() (v int) { v = 1 return v // 也可直接return }
- 2). 多個返回值
func Test() (a b, int, c string){ a, b = 1, 2 c = 'str' return }
4. 有參有返回值
3. 遞歸函數
4. 函數類型
- 函數也是一種數據類型
- 通過type來定義
func Add(a, b, int) int {
return a + b
}
type FuncName func(int, int) int
func main() {
var fTest FuncName
fTest = Add
result = fTest(10, 20) // 等價於Add(10, 20)
}
- 回調函數
- 函數有一個參數是函數類型,就是回調函數
type FuncType func(int, int) int func Add(a, b, int) int { return a + b } func Calc(a, b int, f FuncType) (result int) { result = f(a, b) return } func main() { a := Calc(1, 1, Add) }
- 函數有一個參數是函數類型,就是回調函數
5. 匿名函數與閉包
- 匿名函數:沒有函數名字
- 函數的返回值是一個匿名函數,返回一個函數類型
- 閉包
- 以引用方式捕獲外部變量
- 閉包不關心變量和常量是否超出作用域,只要閉包還在使用,這些變量還會存在
- (變量的生命週期不是由它的作用域決定,變量仍隱式存在於函數中)
6. 延遲調用defer
1. defer的作用
- 關鍵字defer用於延遲一個函數或方法
- 只能出現在函數或方法的內部
2. 多個defer執行順序
- 後進先出的順序執行
- 哪怕函數或某個延遲調用發生錯誤,這些調用仍舊會被執行
3. defer與匿名函數結合使用
func main() {
a, b := 10, 20
defer func(x int) {
fmt.Println("defer:", x, b) // b 閉包引用
}(a)
a += 10
b += 100
fmt.Printf("a = %d, b = %d\n", a, b)
/*
運行結果:
a = 20, b = 120
defer: 10 120
*/
}
7. 獲取命令行參數
package main
import (
"fmt"
"os"
)
func main() {
args := os.Args //獲取用戶輸入的所有參數
//如果用戶沒有輸入,或參數個數不夠,則調用該函數提示用戶
if args == nil || len(args) < 2 {
fmt.Println("err: xxx ip port")
return
}
ip := args[1] //獲取輸入的第一個參數
port := args[2] //獲取輸入的第二個參數
fmt.Printf("ip = %s, port = %s\n", ip, port)
}
8. 作用域
- 作用域爲已聲明標識符所表示的常量、類型、變量,函數或包在源代碼中的作用範圍
1. 局部變量
- 定義在 { } 裏面的變量就是局部變量,只能在 { } 裏有效
- 執行到定義變量那句時,纔開始分配空間,離開作用域會自動釋放
2. 全局變量
- 在函數體外聲明的變量稱之爲全局變量
- 全局變量可以在整個包甚至外部包(被導出後)使用
3. 不同作用域同名變量
- 在不同作用域可以聲明同名的變量
- 其訪問原則爲:
- 在同一個作用域內,就近原則訪問最近的變量
- 如果此作用域沒有此變量聲明,則訪問全局變量
- 如果全局變量也沒有,則報錯。