1. 程式人生 > >go語言學習(二):函式、閉包、工程目錄

go語言學習(二):函式、閉包、工程目錄

1.不定引數型別
func MyFun01(a int, b int){
//a = 111
fmt.Println(“a =”, a,b)
}
//…type不定引數型別
func MyFunc02(args …int){ //傳遞的實參可以是0個或者多個
//fmt.Println(“len(args) =”,len(args)) //獲取使用者傳遞引數的個數
for i:=0;i<len(args);i++{
fmt.Printf(“args[%d] = %d\n”, i, args[i])
}
fmt.Println("===================")
//range返回2個值,第一個是下標,第二個是下標對應的資料
for i,data := range args{
fmt.Printf(“args[%d] = %d\n”, i, data)
}
}

func main() {
MyFunc02()
fmt.Println("+++++++++++++++++")
MyFunc02(1)
fmt.Println("+++++++++++++++++")
MyFunc02(1,2,3)
}
2.不定引數的傳遞

func myfunc(tmp ...int){
   for _,data := range tmp{
      fmt.Println("data =", data)
   }
}

func myfunc2(tmp ...int){
   for _,data := range tmp{
      fmt.Println("data =", data)
   }
}

func test(args ...int){
   //全部元素傳遞給myfunc
   //myfunc(args...)

   //只想把後2個引數傳遞給另外一個函式使用
   //myfunc2(args[0:2]...) //從0到2(不包括2)傳遞過去
   myfunc2(args[2:]...) //從args[2]開始(包括本身),把後面所有元素傳遞過去
}

func main() {
    test(1, 2, 3)
}

3.單返回值常用寫法

func myfunc01() int{
   return 666
}

//給返回值起一個變數名,go推薦寫法
//常用寫法
func myfunc02() (result int) {
   result = 666
   return
}
func main() {
   //無參返回值函式呼叫
    var a int
    a = myfunc01()
    fmt.Println("a =", a)

    //自動推導型別
    b := myfunc02()
    fmt.Println("b =", b)
}

4.多個返回值

//多個返回值
func myfunc01() (int, int, int){
    return 1, 2, 3
}

//go官方推薦寫法
func myfunc02() (a int, b int, c int){
   a, b, c = 111, 222, 333
   return
}

func myfunc03() (a, b, c int){
   a, b, c = 111, 222, 333
   return
}
func main() {
   //函式呼叫
   a, b, c := myfunc03()
   fmt.Println(a, b, c)
}

求最大最小值

//函式名小寫私有,大寫公有
func MaxandMin(a, b int) (max, min int){
   if a>b{
      max=a
      min=b
   }else {
      max=b
      min=a
   }
   return
}
func main() {
   //函式呼叫
   max, min := MaxandMin(10, 20)
   fmt.Println(max, min)
}

5.遞迴(斐波那且數列,漢諾塔)

;i<=100;i++{
      sum+=i
   }
   return
}

func test02(i int) int {
   if i==1{
      return 1
   }
   return i + test02(i-1)
}
func main() {
   //test(3)
   var sum int
   sum = test02(100)
   fmt.Println(sum)
}

函式多型,定義函式變數

func  Add(a, b int) int {
   return a+b
}




//函式也是一種資料型別,通過type給一個函式型別起名
//FuncType它是一個函式型別
type FuncType func(int, int) int  //沒有函式名字,沒有{}

func main() {
   var result int
   result = Add(1,1)
   fmt.Println(result)

   //宣告一個函式型別的變數
   var fTest FuncType
   fTest = Add  //是變數就可以賦值
   result = fTest(10, 20)
   fmt.Println(result)
}

回撥函式實現函式多型性

type FuncType func(int, int) int

//實現想法
func  Add(a, b int) int {
   return a+b
}

func minus(a, b int) int {
   return a-b
}
//回撥函式,函式有一個引數是函式型別,這個函式就是回撥函式
//計算器,可進行四則運算
//多型,多種形態,呼叫同一個介面,不同的表現,可以實現不同的表現,加減乘除的
//現有想法,後面再實現功能
func Calc(a, b int, fTest FuncType) (result int){
   fmt.Println("Calc")
   //result = Add(a, b)  //Add這個函式必須先定義後,才能呼叫
   result = fTest(a, b)  //這個函式還沒有實現
   return
}

func main() {
   a := Calc(1, 1, Add)
   fmt.Println(a)
   b := Calc(1, 1, minus)
   fmt.Println(b)
}

4.閉包

所謂閉包就是一個函式"捕獲"了和它在同一作用域的其他常量和變數,這就意味著當閉包被呼叫的時候,不管程式在什麼地方呼叫,閉包都能使用這些常量或者變數。它不關心這些捕獲了的變數和常量是否已經超出了作用域,所以只有閉包還在使用它,這些變數就還會存在。

匿名函式基本語法

func main() {
   a := 10
   str := "mike"

   //匿名函式,沒有函式名字
   f1 := func() {  //:=自動推導型別,常用
      fmt.Println(a,str)
   }

   f1()

   //給定一個函式型別起別名
   type FuncType func() //函式沒有引數,每有返回值
   //宣告變數
   var f2 FuncType
   f2 = f1
   f2()

   //定義匿名函式,同時呼叫
   func() {
        fmt.Printf("a =%d, str =%\n", a, str)
   }() //後面的()代表給匿名函式傳參,呼叫此匿名函式

   //帶引數的匿名函式
   f3 := func(i, j int){
      fmt.Println(i, j)
   }
   f3(1, 2)

   //定義時同時呼叫
   func(i, j int){
        fmt.Println(i, j)
   }(10,20)

   //匿名函式,有參有返回值
   x, y :=func(i, j int) (max, min int) {
      if i>j{
         max = i
         min = j
      } else {
         max = j
         min = i
      }
      return
   }(10, 20)

   fmt.Println(x,y)
}

在匿名函式內修改外部變數仍同步修改,閉包以引用方式捕獲外部變數

//閉包捕獲外部變數的特點
func main() {
  a := 10
  str := "mike"

  func(){  //在匿名函式內修改外部變數仍同步修改
     //閉包以引用方式捕獲外部變數
     a = 666
     str = "gogogo"
     fmt.Println(a, str)
  }()

  fmt.Println(a, str)
}

變數的生命週期不是由閉包的作用域決定,它不關心這些捕獲了的變數和常量是否已經超出了作用域,所以只有閉包還在使用它,這些變數就還會存在。

func test01() int {
   //函式被呼叫時,x才分配空間,才初始化為0
   var x int
   x++
   return x*x  //函式呼叫完畢,x自動釋放
}

//函式的返回值是一個匿名函式,返回一個型別
func test02() func() int{
   var x int   //沒有初始化,值為0

   return func() int{
      x++
      return x*x
   }
}
func main() {
   //fmt.Println(test01())
   //fmt.Println(test01())
   //fmt.Println(test01())
   //fmt.Println(test01())

   //返回值為一個匿名函式,返回一個函式型別,通過f來呼叫返回的匿名函式
   //變數的生命週期不是由閉包的作用域決定
   f := test02()
   fmt.Println(f())  //1
   fmt.Println(f())  //4
   fmt.Println(f())  //9
   fmt.Println(f())  //16
}

獲取命令列引數

package main

import (
   "fmt"
   "os"
)

func main() {
   //接收使用者傳遞的引數,是以字串方式傳遞
   list := os.Args

   n := len(list)
   fmt.Println("n = ", n)

   for i := 0; i < n;i++{
      fmt.Printf("list[%d] = %s\n",i,list[i])
   }

   for i, data := range list {
      fmt.Printf("list[%d] = %s\n",i,data)
   }
}

全域性變數:定義在函式外部的變數是全域性變數
區域性變數:定義在{}裡面的變數就是區域性變數,只能在大括號內有效。執行到定義變數那句話,才開始分配空間,離開作用域自動釋放
不同作用域允許定義同名變數,遵循就近原則
5.工作區
go程式碼必須放在工作區中,工作區其實就是一個對英語特定工程的目錄
它包含三個子目錄:src目錄、pkg目錄和bin目錄

  • src目錄:用於以程式碼包的形式組織並儲存Go原始碼檔案(比如:.go、.c、.h)。分檔案程式設計(多個原始檔),必須放在src目錄。
    1)如果有多個檔案或多個包,配置src同級目錄的絕對路徑。
    2)如果要自動生成pkg、bin目錄。需要使用go install命令。除了要配置GOPATH環境變數,還要配置GOBIN環境變數

  • pkg目錄:用於存放經由gp install命令構建安裝後的程式碼包(包含go庫原始碼檔案)的".a"歸檔檔案

  • bin目錄:與pkg目錄類似,在通過go install命令完成安裝後,儲存由go命令原始碼生成的可執行檔案

分檔案程式設計:

同級目錄:

  • 同一個目錄,包名必須一樣
  • 同一個目錄,呼叫別的檔案的函式,直接呼叫即可,無需包名引用

不同級目錄:

  • 不同目錄,包名不一樣
  • 呼叫不同包裡面的函式,格式:包名.函式名()
  • 呼叫別的包的函式,這個包函式名字如果是小寫,無法讓別人呼叫;要想別人能呼叫,必須首字母大寫

main函式和init函式執行流程:
先執行匯入包中的函式,再執行init(),最後執行main()。但有時使用者可能需要匯入一個包,但是不需要引用這個包的識別符號,在這種情況,可使用空白識別符號_來重新命名這個匯入:

import _ "fmt"