Go語言基礎之函數

函數

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. 不同作用域同名變量
  • 在不同作用域可以聲明同名的變量
  • 其訪問原則爲:
    • 在同一個作用域內,就近原則訪問最近的變量
    • 如果此作用域沒有此變量聲明,則訪問全局變量
    • 如果全局變量也沒有,則報錯。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章