91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go編程基礎-學習1

發布時間:2020-06-27 11:30:17 來源:網絡 閱讀:1184 作者:1350368559 欄目:開發技術

Go編程基礎-學習

本內容為自己學習go知識記錄的筆記,方便復習查看
筆記內容參考無聞老師的github:https://github.com/Unknwon/go-fundamental-programming
課程視頻內容:百度網盤(提取碼:mgom)
筆記內容參考:Go編程基礎-課堂講義

1. 什么是Go?

Go是一門 并發支持 、垃圾回收 的 編譯型 系統編程語言,旨在創造一門具有在靜態編譯語言的 高性能 和動態語言的 高效開發 之間擁有良好平衡點的一門編程語言。

2. Go的主要特點有哪些?

類型安全 和 內存安全
以非常直觀和極低代價的方案實現 高并發
高效的垃圾回收機制
快速編譯(同時解決C語言中頭文件太多的問題)
為多核計算機×××能提升的方案
UTF-8編碼支持

3.Go存在的價值是什么?

Go在谷歌:以軟件工程為目的的語言設計

4.Go是記事本編程嗎?

包括VIM,IDEA,Sublime Text,Eclipse等眾多知名IDE均已支持

5.Go目前有多少實際應用和資源?

全球最大視頻網站 Youtube(谷歌)
七牛云存儲以及旗下網盤服務(Q盤)
愛好者開發的Go論壇及博客
已用Go開發服務端的著名企業:谷歌、盛大、七牛、360
其它海量開源項目:go-wiki、Go Walker、Go Language Resources

6.Go發展成熟了嗎?

作為一門2009年才正式發布的編程語言,Go是非常年輕的,因此不能稱為一門成熟的編程語言,但開發社區每天都在不斷更新其核心代碼,給我們這些愛好者給予了很大的學習和開發動力。

7.Go的愛好者多嗎?

以Google Group為主的郵件列表每天都會更新10至20帖,國內的Go愛好者QQ群和論壇每天也在進行大量的討論,因此可以說目前Go愛好者群體是足夠壯大。

8.安裝Go語言

Go源碼安裝:參考鏈接
Go標準包安裝:下載地址
第三方工具安裝

9.Go環境變量與工作目錄

根據約定,GOPATH下需要建立3個目錄:
bin(存放編譯后生成的可執行文件)
pkg(存放編譯后生成的包文件)
src(存放項目源碼)

Go編程基礎-學習1

10.Go命令

在命令行或終端輸入go即可查看所有支持的命令

11.Go常用命令簡介
go get:獲取遠程包(需 提前安裝 git或hg)
go run:直接運行程序
go build:測試編譯,檢查是否有編譯錯誤
go fmt:格式化源碼(部分IDE在保存時自動調用)
go install:編譯包文件并編譯整個程序
go test:運行測試文件
go doc:查看文檔(CHM手冊)
12.程序的整體結構

Go編程基礎-學習1

13.Go開發工具安裝及配置

本套教程主要使用 Sublime Text
其它IDE安裝方案:參考鏈接
Sublime Text
下載Sublime Text:官方網站
安裝gosublime(破解版可能無法安裝):安裝指令
Sublime Text 2 入門及技巧

14.Go語言版”Hello world!”

Go編程基礎-學習1
輸出:hello.go
Go編程基礎-學習1

15.Go內置關鍵字(25個均為小寫)
- break        default           func        interface        select
- case          defer              go           map               struct
- chan          else                goto       package        switch
- const         fallthrough    if             range             type
- continue   for                  import    return             var 
16.Go注釋方法
//   單行注釋
/* */  多行注釋
17.Go程序的一般結構:basic_structure.go

Go程序是通過 package 來組織的(與python類似)
只有 package 名稱為 main 的包可以包含 main 函數
一個可執行程序 有且僅有 一個 main 包
通過 import 關鍵字來導入其它非 main 包
通過 const 關鍵字來進行常量的定義
通過在函數體外部使用 var 關鍵字來進行全局變量的聲明與賦值
通過 type 關鍵字來進行結構(struct)或接口(interface)的聲明
通過 func 關鍵字來進行函數的聲明

18.Go導入 package 的格式

Go編程基礎-學習1 Go編程基礎-學習1Go編程基礎-學習1

  • 導入包之后,就可以使用格式<PackageName>.<FuncName>
    來對包中的函數進行調用
    如果導入包之后 未調用 其中的函數或者類型將會報出編譯錯誤:
    Go編程基礎-學習1

    19.package 別名

    當使用第三方包時,包名可能會非常接近或者相同,此時就可以使用
    別名來進行區別和調用
    Go編程基礎-學習1 Go編程基礎-學習1 Go編程基礎-學習1

    20.省略調用

    不建議使用,易混淆
    不可以和別名同時使用
    Go編程基礎-學習1

    21.可見性規則

    Go語言中,使用 大小寫 來決定該 常量、變量、類型、接口、結構
    或函數 是否可以被外部包所調用:
    根據約定,函數名首字母 小寫 即為private
    Go編程基礎-學習1
    函數名首字母 大寫 即為public
    Go編程基礎-學習1

    22.既然導入多個包時可以進行簡寫,那么聲明多個 常量、全局變量

    或一般類型(非接口、非結構)是否也可以用同樣的方法呢?
    Go編程基礎-學習1Go編程基礎-學習1Go編程基礎-學習1

    23.Go基本類型

    布爾型:bool

    • 長度:1字節
    • 取值范圍:true, false
    • 注意事項:不可以用數字代表true或false
      整型:int/uint
    • 根據運行平臺可能為32或64位
      8位整型:int8/uint8
    • 長度:1字節
    • 取值范圍:-128~127/0~255
      字節型:
    • byte(uint8別名)
      16位整型:int16/uint16
    • 長度:2字節
    • 取值范圍:-32768~32767/0~65535
      32位整型:int32(rune)/uint32
    • 長度:4字節
    • 取值范圍:-2^32/2~2^32/2-1/0~2^32-1
      64位整型:int64/uint64
    • 長度:8字節
    • 取值范圍:-2^64/2~2^64/2-1/0~2^64-1
      浮點型:float32/float64
    • 長度:4/8字節
    • 小數位:精確到7/15小數位
      復數:complex64/complex128
    • 長度:8/16字節
      足夠保存指針的 32 位或 64 位整數型:uintptr
      其它值類型:
    • array、struct、string
      引用類型:
    • slice、map、chan
      接口類型:inteface
      函數類型:func
      類型零值
      零值并不等于空值,而是當變量被聲明為某種類型后的默認值,通常情況下值類型的默認值為0,bool為false,string為空字符串
      24.類型自定義別名,定義string類型的自定義別名是:文本,定義b是 文本 類型,給b賦值,輸出ok

      type (
      bype int8
      rune int32
      文本 string
      )

    func main() {
    var b 文本
    b = "中文類型名字"
    fmt.Println(b)
    }
    $ go run basic_struct.go
    中文類型名字

    25.單個變量的聲明與賦值

    變量的聲明格式:var <變量名稱> <變量類型>
    變量的賦值格式:<變量名稱> = <表達式>
    聲明的同時賦值:var <變量名稱> [變量類型] = <表達式>
    Go編程基礎-學習1

    26.多個變量的聲明與賦值,
    • 全局變量的聲明可使用 var() 的方式進行簡寫
    • 全局變量的聲明不可以省略 var,但可使用并行方式
    • 所有變量都可以使用類型推斷
    • 局部變量不可以使用 var() 的方式簡寫,只能使用并行方式
    • 全局變量不可以使用":"符號 ":"只用于方法體內使用,":"是用來代替var的,所以全局變量var a int = 1不能使用:,否則兩個var豈不重復報錯?
      三種定義局部變量的方法:
      func main() {
      var a, b, c, d int = 1, 2, 3, 4
      var a, b, c, d = 1, 2, 3, 4
      a, b, c, d := 1, 2, 3, 4
      fmt.Println(a)
      fmt.Println(b)
      fmt.Println(c)
      fmt.Println(d)
      }
      用空白符號: 接受2的返回值
      func main() {
      a,
      , c, d := 1, 2, 3, 4
      fmt.Println(a)
      fmt.Println(c)
      fmt.Println(d)
      }
      Go編程基礎-學習1Go編程基礎-學習1
      27.變量的類型轉換

      Go中不存在隱式轉換,所有類型轉換必須顯式聲明
      轉換只能發生在兩種相互兼容的類型之間
      類型轉換的格式:

    • <ValueA> [:]= <TypeOfValueA>(<ValueB>)
      Go編程基礎-學習1
      嘗試執行以下代碼,看結果輸出什么?

      Go編程基礎-學習1

package main
import (
    "fmt"
)
func main() {
    //fmt.Println("hello world")
    var a int = 65
    fmt.Println(a)
    b := string(a)
    fmt.Println(b)
}    
daixuandeMacBook-Pro:學習go daixuan$ go run hello.go
65
A
如果我就是想輸出字符串65,怎么辦?
package main
import (
    "fmt"
    "strconv"
)
func main() {
    var a int = 65
    b := strconv.Itoa(a)
    fmt.Println(b)
}
$ go run basic_struct.go
65

string() 表示將數據轉換成文本格式,因為計算機中存儲的任何東西
本質上都是數字,因此此函數自然地認為我們需要的是用數字65表示
的文本 A。

28.常量的定義

常量的值在編譯時就已經確定
常量的定義格式與變量基本相同
等號右側必須是常量或者常量表達式
常量表達式中的函數必須是內置函數
Go編程基礎-學習1

29.常量的初始化規則

在定義常量組時,如果不提供初始值,則表示將使用上行的表達式
使用相同的表達式不代表具有相同的值
Go編程基礎-學習1
Go編程基礎-學習1

package main
import (
    "fmt"
)
const (
    a, b = 1, "2" 
    c, d //這里兩個變量c,d使用初始化規則,值等于上一行表達式,注意每一行的常量個數相同
)
func main() {
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
    fmt.Println(d)
}
$ go run basic_struct.go
1
2
1
2
30.枚舉

iota是常量的計數器,從0開始,組中每定義1個常量自動遞增1
通過初始化規則與iota可以達到枚舉的效果
每遇到一個const關鍵字,iota就會重置為0

package main
import (
    "fmt"
)
const (
    a = "A"
    b           //b初始化規則b=a="A"
    c = iota    //已經有2個常量a,b,所以c=2
    d           //注意:這里d套用了c的常量表達式d=iota,已經有3個常量a,b,c,所以d=3
)
const (  
    e = iota  //每遇到一個const關鍵字,iota就會重置為0,所以e=iota=0
    f     //f套用了e的常量表達式f=iota,e=0,f=e+1=1
)
func main() {
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
    fmt.Println(d)
    fmt.Println(e)
    fmt.Println(f)
}
go run basic_struct.go
A
A
2
3
0
1
31.運算符

Go中的運算符均是從左至右結合
優先級(從高到低)
^ ! (一元運算符)

  • / % << >> & &^
    • ^(異或,相同為0,不同為1) (二元運算符)
      == != < <= >= >
      <- (專門用于channel)
      &&
      package main
      import (
      "fmt"
      )
      /*
      6  :0110
      11:1011
      &  0010 = 2
      |  1111 =15
      ^  1101 =13   //異或,相同為0,不同為1,1^0=1,0^1=1,0^0=0,1^1=0
      &^ 0100 = 4 //表示如果B后邊的為1,需要強制將A的改為0
      */
      func main() {
      fmt.Println(6 & 11)
      fmt.Println(6 | 11)
      fmt.Println(6 ^ 11)
      fmt.Println(6 &^ 11)
      }
      go run basic_struct.go
      2
      15
      13
      4
      32.請嘗試結合常量的iota與<<運算符實現計算機儲存單位的枚舉

      Go編程基礎-學習1
      Go編程基礎-學習1

      33.指針

      Go雖然保留了指針,但與其它編程語言不同的是,在Go當中不
      支持指針運算以及”->”運算符,而直接采用”.”選擇符來操作指針
      目標對象的成員
      操作符”&”取變量地址,使用”*”通過指針間接訪問目標對象
      默認值為 nil 而非 NULL
      遞增遞減語句

      func main() {
      a := 1
      var p *int = &a //p是指向a地址(0xc420016088)的int指針
      fmt.Println(p)
      fmt.Println(*p)    
      }
      $go run basic_struct.go  
      0xc420016088
      1
      *p取地址內的值1
      func main() {
      a := 1
      var p = &a
      fmt.Println(p)
      fmt.Println(*p)
      }
      $ go run basic_struct.go
      0xc420016088
      1

      在Go當中,++ 與 -- 是作為語句而并不是作為表達式
      簡單理解為:

      /允許:
      a :=1
      a++
      //不允許,報錯
      a :=1
      a  := a++
      34.判斷語句if

      條件表達式沒有括號
      支持一個初始化表達式(可以是并行方式)
      左大括號必須和條件語句或else在同一行
      支持單行模式
      初始化語句中的變量為block級別,同時隱藏外部同名變量1.0.3版本中的編譯器BUG

      func main() {
      a := 10 
      if a := 3; a > 1 {  //可以在if中初始化a:=3,但是a=3僅僅在if中有效
      fmt.Println(a)
      }
      fmt.Println(a) //如果沒有提前定義a :=10 ,這里會報錯
      }
      go run basic_struct.go
      3
      10

      Go編程基礎-學習1

      func main() {
      a := true
      if a, b, c := 1, 2, 3; a+b+c > 6 { //可以在if中初始化a:=1,但是a=1僅僅在if中有效,if外a=true
      fmt.Println("大于6")
      } else {
      fmt.Println("小于等于6")
      fmt.Println(a)
      }
      fmt.Println(a)
      }
      $ go run basic_struct.go
      小于等于6
      1
      true
      35.循環語句for,3種形式

      Go只有for一個循環語句關鍵字,但支持3種形式
      初始化和步進表達式可以是多個值
      條件語句每次循環都會被重新檢查,因此不建議在條件語句中
      使用函數,盡量提前計算好條件并以變量或常量代替
      左大括號必須和條件語句在同一行
      (1)for+if

      func main() {
      a := 1
      for {
      a++
      if a > 3 {
          break
      }
      fmt.Println(a)
      }
      fmt.Println("Over")
      }
      $ go run basic_struct.go
      2
      3
      Over

      (2)for 自帶判斷條件

      func main() {
      a := 1
      for a <= 3 {
      a++
      fmt.Println(a)
      }
      fmt.Println("Over")
      }
      $ go run basic_struct.go
      2
      3
      4
      Over

      (3經典方式

      func main() {
      a := 1
      for i := 0; i < 3; i++ {
      a++
      fmt.Println(a)
      }
      fmt.Println("Over")
      }
      $ go run basic_struct.go
      2
      3
      4
      Over
      36.選擇語句switch

      可以使用任何類型或表達式作為條件語句
      不需要寫break,一旦條件符合自動終止
      如希望繼續執行下一個case,需使用fallthrough語句
      支持一個初始化表達式(可以是并行方式),右側需跟分號
      左大括號必須和條件語句在同一行

      func main() {
      a := 1
      switch a {
      case 0:
      fmt.Println("a=0")
      case 1:
      fmt.Println("a=1")
      default:
      fmt.Println("None")
      }
      }
      $ go run basic_struct.go
      a=1
      func main() {
      a := 1
      switch {
      case a >= 0:
      fmt.Println("a=0")  //a=0滿足條件,打印a=0跳出
      case a >= 1:
      fmt.Println("a=1")
      default:
      fmt.Println("None")
      }
      }
      $ go run basic_struct.go
      a=0
      func main() {
      a := 1
      switch {
      case a >= 0:
      fmt.Println("a=0") //a=0滿足條件,打印a=0,有fallthrough不跳出,檢查下一個
      fallthrough
      case a >= 1:
      fmt.Println("a=1")
      default:
      fmt.Println("None")
      }
      }
      $ go run basic_struct.go
      a=0
      a=1
      func main() {
      switch a := 1; { //在switch中定義a,作用于switch內部,外部調用失敗
      case a >= 0:
      fmt.Println("a=0")
      fallthrough
      case a >= 1:
      fmt.Println("a=1")
      default:
      fmt.Println("None")
      }
      }
      $ go run basic_struct.go
      a=0
      a=1
      37.跳轉語句goto, break, continue

      三個語法都可以配合標簽使用,實現跳出多層循環
      標簽名區分大小寫,若不使用會造成編譯錯誤
      Break與continue配合標簽可用于多層循環的跳出
      Goto是調整執行位置,與其它2個語句配合標簽的結果并不相同

      func main() {
      LABEL1:
      for {
      for i := 0; i < 10; i++ {
          if i > 3 {
              break LABEL1
          }
      }
      }
      fmt.Println("ok")
      }
      $ go run basic_struct.go
      ok
      func main() {
      for {
      for i := 0; i < 10; i++ {
          if i > 3 {
              goto LABEL1
          }
      }
      }
      LABEL1:   //標簽放在最外層循環的外側,確保不死循環,可以跳出
      fmt.Println("ok")
      }
      $ go run basic_struct.go
      ok
      func main() {
      LABEL1:
      for i := 0; i < 10; i++ { //把有限循環放在最外面,那么continue最終會結束,不會死循環
      for {
          continue LABEL1
          fmt.Println(i)
      }
      }
      fmt.Println("ok")
      }
      $ go run basic_struct.go
      ok
      將下圖中的continue替換成goto,程序運行的結果還一樣嗎?

      請嘗試并思考為什么。
      Go編程基礎-學習1

func main() {
LABEL1:
    for i := 0; i < 10; i++ {
        for {
            fmt.Println(i)
            continue LABEL1
        }
    }
    fmt.Println("ok")
}
$ go run basic_struct.go
0
1
2
3
4
5
6
7
8
9
ok
func main() {
LABEL1:
    for i := 0; i < 10; i++ {
        for {
            fmt.Println(i)
            goto LABEL1
        }
    }
    fmt.Println("ok")
}
$ go run basic_struct.go
0
0
0
......
因為一執行循環,輸出0后,goto到label1,用重新開始循環,重新輸出0之后,又調到label1,又進入循環,無線下去輸出0,死循環
38.數組Array

定義數組的格式:var <varName> [n]<type>,n>=0
數組長度也是類型的一部分,因此具有不同長度的數組為不同類型

func main() {
    var a [2]int  //初始化int類型數組a,定義為2個元素,默認值為0
    var b [2]int
    b = a
    fmt.Println(b)
}
$ go run basic_struct.go
[0 0]
func main() {
    a := [2]int{1, 1} //初始化int類型數組a,定義為2個元素,初始值為1
    var b [2]int
    b = a
    fmt.Println(b)
}
$ go run basic_struct.go
[1 1]
func main() {
    a := [2]int{1} //初始化int類型數組a,定義為2個元素,初始值1、0
    var b [2]int
    b = a
    fmt.Println(b)
}
$ go run basic_struct.go
[1 0]
func main() {
    a := [20]int{18: 2, 19: 1} //定義數組第19個元素值為2,第20個元素為1
    fmt.Println(a)
}
$ go run basic_struct.go
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1]
func main() {
    a := [...]int{3, 2, 1, 19: 1} //使用...定義數組,第20個元素是1,則數組長度為20
    fmt.Println(a)
}
$ go run basic_struct.go
[3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]

注意區分:
指向數組的指針[100]int -->&[0 0 0 0 0 0 0 0 0 1]
指針數組[100]
int -->[0xc420016088 0xc420016090]

func main() {
    a := [...]int{9: 1}
    var p *[10]int = &a //p是指向數組的指針
    fmt.Println(p)
}
$ go run basic_struct.go
&[0 0 0 0 0 0 0 0 0 1] //數組前面有一個&,p是指向數組的指針
func main() {
    a := [...]int{9: 1}
    var p = &a   //這樣更簡單,p是指向數組的指針
    fmt.Println(p)
}
$ go run basic_struct.go
&[0 0 0 0 0 0 0 0 0 1]
func main() {
    x, y := 1, 2
    a := [...]*int{&x, &y} //定義a是指針類型的數組,保存的數組元素是指向int型的指針:變量x和y的地址 
    fmt.Println(a)
}
$ go run basic_struct.go
[0xc420016088 0xc420016090]

數組在Go中為值類型,傳遞數組是整個拷貝的,其他語言為了節省內存,數組是引用類型。
數組之間可以使用==或!=進行比較,但不可以使用<或>

func main() {
    a := [2]int{1, 2}
    b := [2]int{1, 2}
    fmt.Println(a == b)
}
$ go run basic_struct.go
true
func main() {
    a := [2]int{1, 2}
    b := [2]int{1, 200}
    fmt.Println(a == b)
}
$ go run basic_struct.go
false
//注意:數組長度不同,無法直接比較,否則報錯
func main() {
    a := [2]int{1, 2}
    b := [1]int{10}
    fmt.Println(a == b)
}
$ go run basic_struct.go
# command-line-arguments
./basic_struct.go:17:16: invalid operation: a == b (mismatched types [2]int and [1]int)

可以使用new來創建數組,此方法返回一個指向數組的指針

func main() {
    p := new([10]int)
    fmt.Println(p)
}
$ go run basic_struct.go
&[0 0 0 0 0 0 0 0 0 0]
//可以使用索引直接對數組元素操作
func main() {
    a := [10]int{}
    a[1] = 2      //使用索引直接對數組元素賦值
    fmt.Println(a)
    p := new([10]int)
    p[1] = 2   //使用索引直接對數組元素賦值
    fmt.Println(p)
    fmt.Println(*p)
}
$ go run basic_struct.go
[0 2 0 0 0 0 0 0 0 0]
&[0 2 0 0 0 0 0 0 0 0]
[0 2 0 0 0 0 0 0 0 0]

Go支持多維數組

func main() {
    a := [2][3]int{
        {1, 1, 1},
        {2, 2, 2}}
    fmt.Println(a)
}
$ go run basic_struct.go
[[1 1 1] [2 2 2]]
func main() {
    a := [2][3]int{
        {1: 1},   //給數組元素賦值
        {2: 2}}    //給數組元素賦值
    fmt.Println(a)
}
$ go run basic_struct.go
[[0 1 0] [0 0 2]]

Go語言版冒泡排序

func main() {
    a := []int{5, 2, 6, 3, 9}
    fmt.Println(a)
    num := len(a)
    for i := 0; i < num; i++ {
        for j := i + 1; j < num; j++ {
            if a[i] < a[j] {
                temp := a[i]
                a[i] = a[j]
                a[j] = temp
            }
        }
    }
    fmt.Println(a)
}
$ go run basic_struct.go
[5 2 6 3 9]
[9 6 5 3 2]
39.切片Slice

其本身并不是數組,它指向底層的數組
作為變長數組的替代方案,可以關聯底層數組的局部或全部
為引用類型
可以直接創建或從底層數組獲取生成
使用len()獲取元素個數,cap()獲取容量
一般使用make()創建
如果多個slice指向相同底層數組,其中一個的值改變會影響全部

func main() {
    a := [10]int{1,2,3,4,5,6,7,8,9,0}
    fmt.Println(a)
    s1:=a[5:10]//a[5:10]指的是:a[5,6,7,8,9],不包括a[10]
    fmt.Println(s1)
}
$ go run basic_struct.go
[1 2 3 4 5 6 7 8 9 0]
[6 7 8 9 0]

func main() {
    a := [10]int{1,2,3,4,5,6,7,8,9,0}
    fmt.Println(a)
    s1:=a[5:len(a)]//a[5,6,7,8,9]
    fmt.Println(s1)
}
$ go run basic_struct.go
[1 2 3 4 5 6 7 8 9 0]
[6 7 8 9 0]

func main() {
    a := [10]int{1,2,3,4,5,6,7,8,9,0}
    fmt.Println(a)
    s1:=a[5:]//a[5,6,7,8,9]
    fmt.Println(s1)
}
$ go run basic_struct.go
[1 2 3 4 5 6 7 8 9 0]
[6 7 8 9 0]

func main() {
    a := [10]int{1,2,3,4,5,6,7,8,9,0}
    fmt.Println(a)
    s1:=a[:5]//a[5,6,7,8,9]
    fmt.Println(s1)
}
$ go run basic_struct.go
[1 2 3 4 5 6 7 8 9 0]
[1 2 3 4 5]

make([]T, len, cap)
其中cap可以省略,則和len的值相同
len表示存數的元素個數,cap表示容量

func main() {
    s1:=make([]int,3,10)
    fmt.Println(s1)
}
$ go run basic_struct.go
[0 0 0]
func main() {
    s1:=make([]int,3,10)
    fmt.Println(s1)
    fmt.Println(len(s1),cap(s1))//打印元素個數3和容量10
}
$ go run basic_struct.go
[0 0 0]
3 10
40.Slice與底層數組的對應關系
func main() {
    a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
    sa := a[2:5]
    fmt.Println(string(sa))
}
$ go run basic_struct.go
cde
func main() {
    a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
    sb := a[3:5]
    fmt.Println(string(sb))
}
$ go run basic_struct.go
de

Go編程基礎-學習1

41.Reslice 從slice中獲取新的slice

Reslice時索引以被slice的切片為準
索引不可以超過被slice的切片的容量cap()值
索引越界不會導致底層數組的重新分配而是引發錯誤

func main() {
    a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
    sa := a[2:5]
    fmt.Println(len(sa),cap(sa))//sa元素3,容量是9
    sb := a[3:5]
    fmt.Println(len(sb),cap(sb))//sb元素2,容量是8,比sa少1
    fmt.Println(string(sa))
    fmt.Println(string(sb))
}
$ go run basic_struct.go
3 9
2 8 
cde
de
func main() {
    a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
    sa := a[2:5]
    fmt.Println(len(sa),cap(sa))//sa元素3,容量是9(cdefghijk)
    sb := sa[2:5]
    fmt.Println(len(sb),cap(sb))//sb元素3,容量是7(efghijk)
    fmt.Println(string(sa))
    fmt.Println(string(sb))
}
$ go run basic_struct.go
3 9
3 7
cde
efg
42.Append(重要)

可以在slice尾部追加元素
可以將一個slice追加在另一個slice尾部
如果最終長度未超過追加到slice的容量則返回原始slice
如果超過追加到的slice的容量則將重新分配數組并拷貝原始數據(容量翻倍)

func main() {
    s1 := make([]int,3,6)
    fmt.Printf("%p\n",s1)
    s1 = append(s1,1,2,3)
    fmt.Printf("%v,%p\n",s1,s1)
}
$ go run basic_struct.go
0xc4200180c0              //容量沒有變化,內存地址沒有變化
[0 0 0 1 2 3] 0xc4200180c0
func main() {
    s1 := make([]int,3,6)
    fmt.Printf("%p\n",s1)
    s1 = append(s1,1,2,3)
    fmt.Printf("%v,%p\n",s1,s1)
    s1 = append(s1,1,2,3) //這里容量不夠,重新分配容量(翻倍),拷貝原來元素再追加
    fmt.Printf("%v,%p\n",s1,s1)
}
$ go run basic_struct.go
0xc420092000
[0 0 0 1 2 3],0xc420092000
[0 0 0 1 2 3 1 2 3],0xc420072060
func main() {
    a := []int{1,2,3,4,5}
    s1 := a[2:5]
    s2 := a[1:3]
    fmt.Println(s1,s2)
    s1[0] = 9    //slice指向底層數組,多個slice指向同一個數組時候,其中一個改變,會影響數組,同時影響其他slice值
    fmt.Println(a)
    fmt.Println(s1,s2)
}
$ go run basic_struct.go
[3 4 5] [2 3]
[1 2 9 4 5]
[9 4 5] [2 9]
func main() {
    a := []int{1,2,3,4,5}
    s1 := a[2:5]
    s2 := a[1:3]
    fmt.Println(s1,s2)
    s2=append(s2,1,2,1,1,1,1,1,1,1)//apend元素個數超過slice容量,會指向新的內存地址的底層數組(從a拷貝過來的),此時改變a,不會影響s2的值
    s1[0] = 9
    fmt.Println(a)
    fmt.Println(s1)
    fmt.Println(s2)
}
$ go run basic_struct.go
[3 4 5] [2 3]
[1 2 9 4 5]
[9 4 5]
[2 3 1 2 1 1 1 1 1 1 1]

slice拷貝,以個數少的為準

//把s2拷貝到s1
func main() {
    s1:=[]int{1,2,3,4,5,6}
    s2:=[]int{7,8,9}
    copy(s1,s2) //s2的元素7,8,9會覆蓋s1的前三個元素1,2,3
    fmt.Println(s1)
}
$ go run basic_struct.go
[7 8 9 4 5 6]
//把s1拷貝到s2
func main() {
    s1:=[]int{1,2,3,4,5,6}
    s2:=[]int{7,8,9}
    copy(s2,s1)//把s1的前三個元素1,2,3拷貝覆蓋s2
    fmt.Println(s2,s1)
}
$ go run basic_struct.go
[1 2 3] [1 2 3 4 5 6]
func main() {
    s1:=[]int{1,2,3,4,5,6}
    s2:=[]int{7,8,9}
    copy(s2,s1[3:6]) //把s1的后三個元素拷貝到s2,覆蓋s2元素
    fmt.Println(s2,s1)
}
$ go run basic_struct.go
[4 5 6] [1 2 3 4 5 6]
func main() {
    s1:=[]int{1,2,3,4,5,6}
    s2:=[]int{7,8,9}
    copy(s2[1:3],s1[4:6]) //把s1的后2個元素拷貝到s2的后兩位,覆蓋s2后2個元素,保留第一個元素7
    fmt.Println(s2,s1)
}
$ go run basic_struct.go
[7 5 6] [1 2 3 4 5 6]
43.map

類似其它語言中的哈希表或者字典,以key-value形式存儲數據
Key必須是支持==或!=比較運算的類型,不可以是函數、map或slice
Map查找比線性搜索快很多,但比使用索引訪問數據的類型慢100倍
Map使用make()創建,支持 := 這種簡寫方式

func main() {
    var m map[int]string //定義map,int是key類型,string是value類型
    m=map[int]string{}
    fmt.Println(m)
}
$ go run basic_struct.go
map[]

make([keyType]valueType, cap),cap表示容量,可省略
超出容量時會自動擴容,但盡量提供一個合理的初始值
使用len()獲取元素個數

func main() {
    var m map[int]string=make(map[int]string)
    fmt.Println(m)
}
$ go run basic_struct.go
map[]

func main() {
    var m =make(map[int]string)
    fmt.Println(m)
}
$ go run basic_struct.go
map[]
func main() {
    m :=make(map[int]string)
    fmt.Println(m)
}
$ go run basic_struct.go
map[]
func main() {
    m :=make(map[int]string)
    m[1] = "ok"
    fmt.Println(m)
}
$ go run basic_struct.go
map[1:ok]
func main() {
    m :=make(map[int]string)
    m[1] = "ok"
    a:=m[1]
    fmt.Println(a)
}
ok
func main() {
    m :=make(map[int]string)
    //m[1] = "ok"
    a:=m[1]
    fmt.Println(a)
}
輸出為空

鍵值對不存在時自動添加,使用delete()刪除某鍵值對
使用 for range 對map和slice進行迭代操作

func main() {
    m :=make(map[int]string)
    m[1] = "ok"
    delete(m,1)
    a:=m[1]
    fmt.Println(a)
}
輸出為空
func main() {
    m := make(map[int]map[int]string) //使用make創建初始化m,定義m的value是另一個map[int]string
    m[1]=make(map[int]string)//這里是用make初始化另一個map,作為value賦值給m[1] 
    m[1][1]= "ok"
    a:=m[1][1]
    fmt.Println(a)
}
ok
func main() {
    m := make(map[int]map[int]string)
    m[1]=make(map[int]string) //這里只對m[1]初始化了,沒有對m[2]初始化,所以把ok賦值給nil報錯
    m[2][1]= "ok"
    b:=m[2][1]
    fmt.Println(b)
}
panic: assignment to entry in nil map

goroutine 1 [running]:
main.main()
    /Users/daixuan/go/hello.go:8 +0x168

map嵌套map需注意,每一級的map都得初始化,怎么知道map是否被初始化呢?
采用多返回值的方式,當有一個返回值的時候,返回value,當有多個返回值的時候,第二個返回bool類型的值,true或者false

package main
import "fmt"
func main() {
    m := make(map[int]map[int]string)
    m[1]=make(map[int]string)
    m[1][1]= "123"
    a, ok  :=m[1][1] //m[1]被初始化,a=123,不為空,所以ok=true
    b, nok :=m[2][1] //m[2]未被初始化,b=nil,為空,所以nok=false
    fmt.Println(a,ok)
    fmt.Println(b,nok)
}
123 true   
 false
 package main
import "fmt"
func main() {
    m := make(map[int]map[int]string)
    a, ok  :=m[2][1]
    fmt.Println(a,ok) //第一次沒有初始化map,所以ok=false
    if !ok { //這里判斷是否ok==false,那么去初始化map[2](第二級的map)
        m[2]=make(map[int]string)//初始化第二級別map
    }
    m[2][1]="good"http://賦值給第二級map的key=1的value是'good'
    a, ok  =m[2][1]
    fmt.Println(a,ok) //a=good,所以ok=true
}
 false
good true

迭代操作(slice和map都可以迭代操作):

package main
import (
    "fmt"
)
func main()  {
    slice := []int{10,20,30,40}
    for index,value :=range slice { //i是slice的索引,相當于計數器,int型,0,1,2,3,4....,v是slice存儲的值取出賦值給v,修改v的值不會影響slice本身
        if slice[index]==30{
            slice[index]=300 //使用slice[index]=300 可以直接修改slice原始的值為300
            value=400
            fmt.Println(index,value)
            fmt.Println(slice[index]) //使用slice[index]=300 可以直接修改slice原始的值為300
        }
    }
}
2 400
300
package main
import (
    "fmt"
)
func main()  {
    slice := []int{10,20,30,40}
    for _,value :=range slice { //用空白標識符下劃線 _ 來忽略索引值
            fmt.Println(value)
        }
    }
10
20
30
40
package main
import (
    "fmt"
)
func main() {
    m := make(map[int]string)
    m[1]="ok"
    for key, value := range m {
        fmt.Println(key, value)
    }

    info := map[string]string{
        "name": "david",
        "address": "shanghai",
    }
    for k,v := range info{
        fmt.Printf("Key:%s,Value:%s\n",k,v)
    }
}
1 ok
Key:name,Value:david
Key:address,Value:shanghai
package main
import (
    "fmt"
)
func main() {
    sm := make([]map[int]string,5)//定義一個以map為原數類型的slice,定義map方法:m :=map[int]string,定義slice方法:slice := make([]string,5)
    for _, v := range sm { //對slice:sm進程迭代操作
        v = make(map[int]string) //對slice中的map初始化
        v[1] ="OK" //這里對v是個拷貝賦值,不會影響slice本身的值,所以v=map[1:OK],而sm是:[map[] map[] map[] map[] map[]]
        fmt.Println(v)
    }
    fmt.Println(sm)
}
map[1:OK]
map[1:OK]
map[1:OK]
map[1:OK]
map[1:OK]
[map[] map[] map[] map[] map[]]

如果想把slice的值修改掉,怎么辦呢?

package main
import (
    "fmt"
)
func main() {
    sm := make([]map[int]string,5)//定義一個以map為原數類型的slice,定義map方法:m :=map[int]string,定義slice方法:slice := make([]string,5)
    for i := range sm { //對slice:sm進程迭代操作,i=0,1,2,3,4
        sm[i] = make(map[int]string) //對slice中的map初始化
        sm[i][1] ="OK" //這里對第i個切片sm[i]賦值key=1,value="OK",會影響slice本身的值,所以v=map[1:OK],而sm是:[map[1:OK] map[1:OK] map[1:OK] map[1:OK] map[1:OK]]
        fmt.Println(sm[i])
    }
    fmt.Println(sm)
}
map[1:OK]
map[1:OK]
map[1:OK]
map[1:OK]
map[1:OK]
[map[1:OK] map[1:OK] map[1:OK] map[1:OK] map[1:OK]]

map是無序的,不能直接排序,但是我們可以對其key進程間接排序,需要借助slice,實現根據key有序的取出map中的值,實現map的簡介排序

package main
import (
    "fmt"
)
func main() {
    m := map[int]string{1:"a",2:"b",3:"c",4:"d",5:"e"} //定義map,map沒有索引
    s := make([]int,len(m))//定義slice,slice以索引為固定的key
    i :=0
    for k,_ := range m{
        s[i] = k //把map中所有的key存在slice中,但是無序的
        i++
    }
    fmt.Println(s)
}
[5 1 2 3 4]

package main
import (
    "fmt"
    "sort"
)
func main() {
    m := map[int]string{1:"a",2:"b",3:"c",4:"d",5:"e"} //定義map,map沒有索引
    s := make([]int,len(m))//定義slice,slice以索引為固定的key
    i :=0
    for k,_ := range m{
        s[i] = k //把map中所有的key存在slice中
        i++
    }
    sort.Ints(s)//使用sort進程排序,把map中的key排序
    fmt.Println(s)
}
[1 2 3 4 5]
package main
import (
    "fmt"
    "sort"
)
func main() {
    m := map[int]string{1:"a",2:"b",3:"c",4:"d",5:"e"} //定義map,map沒有索引
    fmt.Println(len(m))
    s := make([]int,len(m))//定義slice,slice以索引為固定的key
    i :=0
    for k,_ := range m{
        s[i] = k //把map中所有的key存在slice中
        i++
    }
    sort.Ints(s)
    fmt.Println(s)
    for j := range s{
        fmt.Println(m[j+1])
    }
}
5
[1 2 3 4 5]
a
b
c
d
e
根據在 for range 部分講解的知識,嘗試將類型為map[int]string的鍵和值進行交換,變成類型map[string]int
package main
import (
    "fmt"
)
func main() {
    m1 := map[int]string{1:"a",2:"b",3:"c",4:"d",5:"e"}
    fmt.Println(m1)
    m2 := make(map[string]int)
    for k,v := range m1{
        m2[v] =k
    }
    fmt.Println(m2)
}
map[3:c 4:d 5:e 1:a 2:b]
map[e:5 a:1 b:2 c:3 d:4]

程序正確運行后應輸出如下結果:
Go編程基礎-學習1

44.函數function

Go 函數 不支持 嵌套、重載和默認參數
但支持以下特性:
無需聲明原型、不定長度變參、多返回值、命名返回值參數
匿名函數、閉包
定義函數使用關鍵字 func,且左大括號不能另起一行
函數也可以作為一種類型使用
Go 語言函數定義格式如下:

func function_name( [parameter list] ) [return_types] {
   函數體
}

函數定義解析:
func:函數由 func 開始聲明
function_name:函數名稱,函數名和參數列表一起構成了函數簽名。
parameter list]:參數列表,參數就像一個占位符,當函數被調用時,你可以將值傳遞給參數,這個值被稱為實際參數。參數列表指定的是參數類型、順序、及參數個數。參數是可選的,也就是說函數也可以不包含參數。
return_types:返回類型,函數返回一列值。return_types 是該列值的數據類型。有些功能不需要返回值,這種情況下 return_types 不是必須的。
函數體:函數定義的代碼集合。

定義參數列表是一個int輸入,另一個string輸入,無返回值
fun A(a int,b string){  
}
定義參數列表是一個int輸入,另一個string輸入,只有一個int類型返回值
fun A(a int,b string)int{   
}
定義參數列表是一個int輸入,另一個string輸入,返回類型是一個int+一個string+一個int
fun A(a int,b string)(int,string,int){  
}
定義參數列表是3個int輸入,3個int型輸出
fun A(a int,b int, c int)(a int,b int,c int){   
}
可以簡寫為:
fun A(a,b, c int)(a,b,c int){   
}

命令返回值參數和不命名返回值參數有什么區別呢?
如果你要返回多個返回值的話,而且使用(a,b,c int)簡寫形式的話,你就必須命名返回值,不然它就不知道了

func A() (a,b,c int){
    a,b,c = 1,2,3 //這里不是:=,因為已經在內存中給a,b,c分配過內存地址了
    return a,b,c  //這里也可以直接寫return,因為已經定義了返回值變量和類型(a,b,c int),代碼可讀性要求返回值return后加上變量a,b,c
}

如果這樣定義返回值的話 (int,int,int),就可以不用命名返回值(不定義返回值是a,b,c)

func A() (int,int,int){
    a,b,c := 1,2,3 //這里必須是:=,因為是首次初始化變量
    return a,b,c  //這里不可以只寫return
}

如果A是一串int型的數字,n個,我要計算A長得最大值,怎么寫呢?
使用go中的不定長變參

package main
import "fmt"
func main() {
    A(1,2,3,4,5,6,7)
}
func A(a ...int){  //...就是不定長變參,A就是一個slice,可以打印出來
    fmt.Println(a)
}
輸出:[1 2 3 4 5 6 7]

package main
import "fmt"
func main() {
    A("a",1,2,3,4,5,6,7)
}
func A(b string,a ...int){  //如果A使用了不定長變參"...",不可以在...后邊定義變量b,可以在a之前定義變量b
    fmt.Println(b,a)
}
輸出:a [1 2 3 4 5 6 7]

slice的值拷貝和直接slice地址拷貝有什么區別呢?

package main
import "fmt"
func main() {
    a :=1
    A(a)
    fmt.Println(a)
}
func A(a int){  //如果A使用了不定長變參"..."定義slice A
    a=2  //值拷貝不會修改面main函數中a的值,可以理解為:局部變量修改不會影響全局變量的值
    fmt.Println(a)
}
2
1
package main
import "fmt"
func main() {
    a,b :=1,2
    A(a,b)
    fmt.Println(a,b)
}
func A(s ...int){  //如果A使用了不定長變參"..."定義slice s
    s[0]=3//a=3,值拷貝不會影響main函數的內部a的值
    s[1]=4//b=4,值拷貝不會影響main函數的內部b的值
    fmt.Println(s)
}
[3 4]
1 2
package main
import "fmt"
func main() {
    s1 := []int{1,2,3,4}
    A(s1)
    fmt.Println(s1)
}
func A(s []int){  //如果A使用了不定長變參"..."定義slice A
    s[0]=5//在A()函數的內部修改影響到了main函數中的s1的值,這里拿到了slice的地址,拷貝修改了slice內存地址中的值,實際上就是對slice本身進行操作
    s[1]=6
    s[2]=7
    s[3]=8
    fmt.Println(s)
}
[5 6 7 8]
[5 6 7 8]

如果我想對這種int,string,也進行內存地址值得拷貝覆蓋操作,怎么做?
采用指針地址值傳遞,先取出地址,再賦值

package main
import "fmt"
func main() {
    a :=1
    A(&a)//調用A()函數,由于A()要求輸出是指針類型(一個地址值0xxxx),所有輸入&a符合輸入要求&a=0xxxx
    fmt.Println(a)//這里也打印2,說明內存中的*a的值已經被修改
}
func A(a *int){ //定義了指針類型的a,a可能的值是a=0xxxxx
    *a=2 //把內存地址為0xxxx的變量*a重新賦值為2
    fmt.Println(*a)//打印*a的變量值,
}
2
2

函數也是一種數據類型,給個例子

package main
import "fmt"
func main() {
    a :=A //這里a就是A的復制品
    a()
}
func A(){
    fmt.Println("Func A")
}
Func A

什么是匿名函數呢?

package main
import "fmt"
func main() {
    a := func() { //定義a是匿名函數,可以調用并且打印Func A
        fmt.Println("Func A")
    }
    a()
}
Func A

那么什么是閉包?

package main
import "fmt"
func main() {
    f := closure(10) //調用閉包函數closure(),返回一個匿名函數給f,賦值x=10
    /*
    此時f就是匿名函數:
    func(y int)int {
        fmt.Printf("%p\n",&x)  
        return x + y
    }
    */
    fmt.Println(f(1)) //第一次調用func(),x=10,y=1,return 11
    fmt.Println(f(2)) //第二次調用func(),x=10,y=2,return 12
}
func closure(x int) func(int) int { //閉包函數的作用是返回一個匿名函數
    fmt.Printf("%p\n",&x) //第一次調用閉包函數打印x變量地址0xc420012070
    return func(y int)int {
        fmt.Printf("%p\n",&x)  //第二、三次調用閉包函數打印x變量地址0xc420012070,三次相同,
        return x + y
    }
}
0xc420012070
0xc420012070
11
0xc420012070
12

實例
以下實例為 max() 函數的代碼,該函數傳入兩個整型參數 num1 和 num2,并返回這兩個參數的最大值:

//函數返回兩個數的最大值
func max(num1, num2 int) int {
// 聲明局部變量 
var result int
if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result 
}

函數調用
當創建函數時,你定義了函數需要做什么,通過調用改函數來執行指定任務。

調用函數,向函數傳遞參數,并返回值,例如:

package main
import "fmt"
func main() {
   /* 定義局部變量 */
   var a int = 100
   var b int = 200
   var ret int
   /* 調用函數并返回最大值 */
   ret = max(a, b)
   fmt.Printf( "最大值是 : %d\n", ret )
}
/* 函數返回兩個數的最大值 */
func max(num1, num2 int) int {
   /* 定義局部變量 */
   var result int
   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result 
}
以上實例在 main() 函數中調用 max()函數,執行結果為:
最大值是 : 200

函數返回多個值
Go 函數可以返回多個值,例如:

package main
import "fmt"
func swap(x, y string) (string, string) {
   return y, x
}
func main() {
   a, b := swap("Mahesh", "Kumar")
   fmt.Println(a, b)
}
以上實例執行結果為:
Kumar Mahesh
  • 函數參數
    函數如果使用參數,該變量可稱為函數的形參。
    形參就像定義在函數體內的局部變量。
    調用函數,可以通過兩種方式來傳遞參數:
傳遞類型 描述
值傳遞 值傳遞是指在調用函數時將實際參數復制一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數。
引用傳遞 引用傳遞是指在調用函數時將實際參數的地址傳遞到函數中,那么在函數中對參數所進行的修改,將影響到實際參數。

默認情況下,Go 語言使用的是值傳遞,即在調用過程中不會影響到實際參數。

  • 函數用法
    函數用法
    描述
    函數作為值 函數定義后可作為值來使用
    閉包 閉包是匿名函數,可在動態編程中使用
    方法 方法就是一個包含了接受者的函數
    45.defer

    執行方式類似其它語言中的析構函數,在函數體執行結束后
    按照調用順序的相反順序逐個執行(先進后出,后進先出)
    即使函數發生嚴重錯誤也會執行
    支持匿名函數的調用
    常用于資源清理、文件關閉、解鎖以及記錄時間等操作
    通過與匿名函數配合可在return之后修改函數計算結果
    如果函數體內某個變量作為defer時匿名函數的參數,則在定義defer時即已經獲得了拷貝,否則則是引用某個變量的地址
    Go 沒有異常機制,但有 panic/recover 模式來處理錯誤
    Panic 可以在任何地方引發,但recover只有在defer調用的函數中有效

    package main
    import "fmt"
    func main() {
    fmt.Println("a")
    defer fmt.Println("b")
    defer fmt.Println("c")//先調用打印c,在調用打印b
    }
    a
    c
    b
    package main
    import "fmt"
    func main() {
    for i :=0;i < 3 ;i ++{
        defer fmt.Println(i)
    }
    }
    2 //打印結果是2,1,0,而不是0,1,2
    1
    0
    package main
    import "fmt"
    func main() {
    for i :=0;i < 3 ;i ++{//這里循環結束的時候i=3,閉包中的匿名函數調用的i=3,所以三次打印出來的值都是3
        defer func(){
            fmt.Println(i) //引用局部變量i,在退出for循環體的時候,i=3,在main函數return的時候,開始執行defer語句,i=3,所以全部打印3
        }() //這個括號的意思是調用這個函數,可以理解為defer a()
    }
    }
    3
    3
    3
    package main
    import "fmt"
    func main() {
    A()
    B()
    C()
    }
    func A()  {
    fmt.Println("Func A")
    }
    func B() {
    defer func(){//定義好defer遇到panic后Recover,必須在出現panic之前就定義好defer處理函數
        if err := recover();err !=nil{
            fmt.Println("Recover in B")
        }
    }()
    panic("Panic in B ")//定義panic
    }
    func C(){
    fmt.Println("Func C")
    }
    Func A
    Recover in B
    Func C
    運行以下程序并分析輸出結果
    package main
    import "fmt"
    func main() {
    var fs = [4]func(){}//定義fs是func類型的slice
    for i :=0;i<4;i++{
        defer fmt.Println("defer i = ",i)//i作為一個參數,值拷貝傳遞,正常輸出0,1,2,3,但是使用了defer定義,所以出書3,2,1,0
        defer func(){
            fmt.Println("defer_closure i =",i)//閉包匿名函數,外層循環結束,i=4,所以打印defer_closure i = 4
            }()
        fs[i] = func() {
            fmt.Println("closure i =",i)//先將這些匿名函數存在func類型的slice中,這里i來自于外層的for循環,外層for循環結束之后引用地址內容值i=4,所以輸出closure i = 4
        }
    }
    for _,f := range  fs{//調用fs,打印closure i = 4
        f()
    }
    }
    closure i = 4
    closure i = 4
    closure i = 4
    closure i = 4
    defer_closure i = 4
    defer i =  3
    defer_closure i = 4
    defer i =  2
    defer_closure i = 4
    defer i =  1
    defer_closure i = 4
    defer i =  0
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

柯坪县| 武汉市| 瑞金市| 南木林县| 叙永县| 曲靖市| 安岳县| 新津县| 邹平县| 手游| 德庆县| 延边| 镇坪县| 沿河| 和林格尔县| 章丘市| 临沂市| 陆川县| 河池市| 浦北县| 溧阳市| 安远县| 屯留县| 丰原市| 叙永县| 东平县| 行唐县| 营山县| 出国| 丽江市| 进贤县| 棋牌| 长垣县| 平安县| 通许县| 桑日县| 龙江县| 蒙城县| 始兴县| 罗甸县| 宜君县|