<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] ## golang 介紹 [官網](https://golang.org/) [百度百科](http://baike.baidu.com/link?url=OIpBeQaglgo2VoUMWgk2JOTfK-NfnC-iHiZ0uxznAHlK1c8CZP4vq7V86s66vSdiy8wlr3ptrJOjCyL91gv6kWmlEygxH1tkXuZcBPvvt_x7X7c8-vKVpxh-Wn0br7O8dxSCvJJc5VyLSDbStB6WP_) > Go語言于2009年11月正式宣布推出,成為開放源代碼項目,并在Linux及Mac OS X平臺上進行了實現,后追加Windows系統下的實現... **注意** 在接下來的學習中請確保go環境已經安裝好,以及GOPATH環境變量和IED也已經準備好。 1. 測試Go版本 `win + r -> cmd -> go version`顯示版本信息表示成功。 ![](https://box.kancloud.cn/9b05b7f9db7ba7355cff454176c75cd0_312x58.png) 2. 測試Go環境`win + r -> cmd -> go env`注意觀察`GOPATH` ![](https://box.kancloud.cn/b6a864cd69ca382c9c4261a6726242ae_470x417.png) 3. GOPATH下最終會存在3個目錄 ![](https://box.kancloud.cn/35de774047ae406b8c8e98224b8c9d7e_409x131.png) * bin(存放編譯后生成的可執行文件) * pkg(存放編譯后生成的包文件) * src(存放項目源碼) ## 第一個Go程序 1. 在`GOPATH/src`目錄下新建`hello.go`文件 2. 編寫代碼如下 ~~~ package main import ( "fmt" ) func main() { fmt.Println("hello , world") } ~~~ 3. 在此處打開命令窗口輸入`go run hello.go` ![](https://box.kancloud.cn/f814781d18f3364947a725524188c3b7_175x21.png) > 一個golang 版本的helloword就完成了。 ## 關鍵字 > Go內置關鍵字(25個均為小寫) |1|2|3|4|5| |--- | --- | --- | --- | --- | |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| ## Go注釋方法 ~~~ // :單行注釋 /* */:多行注釋 ~~~ ## 程序結構 1. Go程序是通過 `package` 來組織的(與`Java`類似) 2. 只有 `package` 名稱為 `main` 的包可以包含 `main` 函數 3. 一個可執行程序**有且僅有**一個 `main` 包 4. 通過 `import` 關鍵字來導入其它非 `main` 包 5. 通過 `const` 關鍵字來進行常量的定義 6. 通過在函數體外部使用 `var` 關鍵字來進行全局變量的聲明與賦值 7. 通過 `type` 關鍵字來進行定義類型的別名,結構(`struct`)或接口(`interface`)的聲明 8. 通過 `func` 關鍵字來進行函數的聲明 ![](https://box.kancloud.cn/872389245bc078becb0d34302d14b7fa_354x486.png) ## 包package ### 導入package ![](https://box.kancloud.cn/e049a0573ec028bd91890a13354040cf_166x79.png) ### package 導入合并 ![](https://box.kancloud.cn/0a7ca234f4401c682003ea972c589ace_159x98.png) **注意** * 導入包之后,就可以使用格式 `PackageName.FuncName`來對包中的函數進行調用 * 如果導入包之后未調用其中的函數或者類型將會報出編譯錯誤: ![](https://box.kancloud.cn/2832b1621f2353b4f556ab5ca7166f47_424x60.png) ### package 別名 ![](https://box.kancloud.cn/2fad40a8d000f532a3ec37fc5850261e_321x220.png) >當使用第三方包時,包名可能會非常接近或者相同,此時就可以使用 別名來進行區別和調用 ### 省略調用 ![](https://box.kancloud.cn/1bf369737dce6f9a37b90cb07dd0897f_295x192.png) ![](https://box.kancloud.cn/f75106ee17520d02b94bf5daaf8201f0_300x72.png) ### 可見性規則 Go語言中,使用**大小寫**來決定該 常量、變量、類型、接口、結構或函數是否可以被外部包所調用: ![](https://box.kancloud.cn/322fc0912f6895b4fadeba4dad0fd92e_250x113.png) **注意** * 首字母大寫即為`public` * 首字母小寫即為`private` #### 課堂作業 既然導入多個包時可以進行簡寫,那么聲明多個 常量、全局變量 或一般類型(非接口、非結構)是否也可以用同樣的方法呢?請自行嘗試 ~~~ //當前程序的包名稱 package main import "fmt" // 常量 const ( ZName = "zxysilent" ZEmail = "zxysilent@goxmail.com" ZPhone = 18284151024 ) // 包級變量(全局變量) var ( name = "zxysilent" email = "zxysilent@foxmail.com" phone = 18284151024 ) // 類型別名 type ( INT int STR string ) // 程序入口 func main() { fmt.Println("hello , word") } ~~~ ## 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`為空字符串 ## 變量&常量 ### 變量 #### 單個變量的聲明與賦值 * 變量的聲明格式:`var <變量名稱> <變量類型>` * 變量的賦值格式:`<變量名稱> = <表達式>` * 聲明的同時賦值:`var <變量名稱> [變量類型] = <表達式>` ~~~ //當前程序的包名稱 package main import "fmt" // 程序入口 func main() { // 變量的申明 var a int //變量的賦值 a = 123 // 變量聲明的同時賦值 var b int = 234 // 類型可省略,編譯器可以自行推斷 var c = 345 //最簡單的 申明和賦值 d := 456 fmt.Println(a, b, c, d) } ~~~ ![](https://box.kancloud.cn/22bac1898614fcbbbf79a3b2bfbcb31b_524x129.png) #### 多個變量的聲明與賦值 * 全局變量的聲明可使用 `var()` 的方式進行簡寫 * 全局變量的聲明不可以省略` var`,但可使用并行方式 * 所有變量都可以使用類型推斷 * 局部變量**不**可以使用` var() `的方式簡寫,只能使用并行方式 > 全局 ~~~ package main var ( // 常規方式 a = "hello" // 并行方式 c, d = 1, 2 //syntax error: unexpected := //e:=5 ) //syntax error: non-declaration statement outside function body //e:=5 // 程序入口 func main() { } ~~~ > 局部 ~~~ package main import "fmt" func main() { // 多個變量的聲明 var a, b, c int // 多個變量的賦值 a, b, c = 1, 2, 3 // 多個變量的聲明同時賦值 var d, e, f int = 4, 5, 6 // 多個變量的省略類型的聲明賦值(編譯器推斷類型 var g, h, i = 7, 8, 9 // 最簡單的多個變量聲明賦值 j, k, l := 10, 11, 12 fmt.Println(a, b, c, d, e, f, g, h, i, j, k, l) } ~~~ ![](https://box.kancloud.cn/2fefd9744a80249fb15f2f4200cd84c4_350x34.png) #### 變量的類型轉換 * Go中不存在隱式轉換,所有類型轉換必須顯式聲明 * 轉換只能發生在兩種相互兼容的類型之間 * 類型轉換的格式: `<ValueA> [:]= <TypeOfValueA>(<ValueB>)` ~~~ package main import "fmt" func main() { // 在相互兼容的兩種類型之進行轉換 var a float32 = 1.1 b := int(a) // 不兼容的轉換無法通過編譯(compile) var c bool = false d := int(c) fmt.Println(a, b, c, d) } ~~~ ![](https://box.kancloud.cn/06e0b0749602a43a3fd4456e7c3d2bc2_496x49.png) #### 課堂作業 請嘗試運行以下代碼,看會發生什么,并思考為什么 ~~~ package main import "fmt" func main() { var a int = 65 b := string(a) fmt.Println(b) } ~~~ ![](https://box.kancloud.cn/d6eec5539e913771e535ff93381d6720_391x30.png) > string() 表示將數據轉換成文本格式,因為計算機中存儲的任何東西 本質上都是數字,因此此函數自然地認為我們需要的是用數字65表示 的文本 A。 ### 常量 #### 常量的定義 * 常量的值在編譯時就已經確定 * 常量的定義格式與變量基本相同 * 等號右側必須是常量或者常量表達式 * 常量表達式中的函數必須是內置函數 ~~~ package main import "fmt" // 定義單個常量 const a int = 1 const b = 'A' const ( text = "12345" lens = len(text) num = b * 100 ) // 同時定義多個常量 const i, j, k = 1, false, "str" const ( d, e, f = i, !j, len(k) ) func main() { fmt.Println(a, b, text, lens, num, i, j, k, d, e, f) } ~~~ ![](https://box.kancloud.cn/0176de65c3212a82e10933dc1aa269de_357x38.png) #### 常量的初始化規則與枚舉 * 在定義常量組時,如果不提供初始值,則表示將使用上行的表達式 * 使用相同的表達式不代表具有相同的值 * iota是常量的計數器,從0開始,組中每定義1個常量自動遞增1 * 通過初始化規則與iota可以達到枚舉的效果 * 每遇到一個const關鍵字,iota就會重置為0 ~~~ package main import "fmt" const ( a = "A" //"A" b //"A c = iota //2 d //3 ) func main() { fmt.Println(a, b, c, d) } ~~~ ![](https://box.kancloud.cn/3f55cc361585f8aa5d3c7a53587cdb31_332x37.png) ~~~ import "fmt" // 星期枚舉 const ( // 第一個不可省略表達式 Monday = iota Tuesday Wednerday Thursday Friday Saturday Sunday ) func main() { fmt.Println(Monday, Tuesday, Wednerday, Thursday, Friday, Saturday, Sunday) } ~~~ ![](https://box.kancloud.cn/712655b1563a5140afce272c063f45ea_341x38.png) ### 運算符 **注意**Go中的運算符均是從左至右結合 優先級(從高到低) 1. `^ ! ` (一元運算符) 2. `* / % << >> & &^` 3. `+ - | ^ ` (二元運算符) 4. `== != < <= >= >` 5. `<- ` (專門用于channel) 6. `&&` 7. `||` ### 其他 #### 指針 Go雖然保留了指針,但與其它編程語言不同的是,在Go當中不支持指針運算以及`->`運算符,而直接采用`.`選擇符來操作指針目標對象的成員 操作符`&`取變量地址,使用`*`通過指針間接訪問目標對象 默認值為 `nil `而非 `NULL` ``` package main func main() { var i = 0 var p = &i println(*p) var p1 *int println(p1==nil) } ``` ![](https://box.kancloud.cn/d8ce3b829f1e3cb5efefe79de66d0bc9_323x46.png) #### 遞增遞減語句 在Go當中,`++` 與 `-- `是作為語句而并不是作為表達式 ``` package main func main() { var i = 0 var i1=i++ println(i1) } ``` ![](https://box.kancloud.cn/acbc0de159df10b650cda9b6b69c4ba0_488x35.png) ## 流程控制 ### if * 條件表達式沒有括號 * 左大括號必須和條件語句或`else`在同一行 ``` package main func main() { // 簡短申明賦值 a,b:=1,2 // 沒有小括號 if a>b{ println(b) }else{ print(a) } } ``` * 支持一個初始化表達式(可以是并行方式) * 支持單行模式 ``` package main func main() { if a,b:=1,2;a>b{ println(b) }else{ print(a) } } ``` * 初始化語句中的變量為`block`級別,同時隱藏外部同名變量 ``` package main func main() { var a =true if a,b:=1,2;a>b{ println(b) }else{ print(a) } println(a) } ``` ### for * Go只有`for`一個循環語句關鍵字,但支持3種形式 * 初始化和步進表達式可以是多個值 * 條件語句每次循環都會被重新檢查,因此**不建議**在條件語句中使用函數,盡量提前計算好條件并以變量或常量代替 * 左大括號必須和條件語句在同一行 ``` package main func main() { for{ //死循環 } } ``` ``` package main func main() { flag := 1 //while for flag < 5 { flag++ println(flag) } } ``` ``` package main func main() { //index:=1 // for ;index < 5;index++ { // println(index) // } for idx:=0;idx<5;idx++{ println(idx) } } ``` ### switch * 可以使用任何類型或表達式作為條件語句 * 不需要寫`break`,一旦條件符合自動終止 * 如希望繼續執行下一個`case`,需使用`fallthrough`語句 * 支持一個初始化表達式(可以是并行方式),右側需跟分號 * 左大括號必須和條件語句在同一行 ``` package main func main() { swh := 1 switch swh { case 0: println(0) case 1: { println(1) println("OK") } default: println("default") } } ``` ``` package main func main() { switch swh:=1;{ case swh > 0: println(0) fallthrough case swh == 1: { println("OK") } default: println("default") } } ``` ### goto, break, continue > 跳轉語句 * 三個語法都可以配合標簽使用 * 標簽名區分大小寫,若不使用會造成編譯錯誤 * `break`與`continue`配合標簽可用于多層循環的跳出**標簽同級** * `goto`是**調整執行位置**,與其它2個語句配合標簽的結果并不相同 ``` package main func main() { FLG: for{ for i:=0;i<10;i++{ if i>2{ break FLG }else{ println(i) } } } } ``` ``` package main func main() { FLG: for i := 0; i < 10; i++ { for { println(i) continue FLG } } } ``` #### 課堂作業 將上面中的continue替換成goto,程序運行的結果還一樣嗎? ## Array * 定義數組的格式:`var <varName> [n]<type>` **n>=0** * **數組長度也是類型的一部分**,因此具有不同長度的數組為不同類型 * 數組之間可以使用`==`或`!=`進行比較,但不可以使用`<`或`>` * 可以使用`new`來創建數組,此方法返回一個指向數組的指針 * 數組在Go中為**值類型** * 注意區分指向數組的指針和指針數組 * Go支持多維數組 ``` package main import "fmt" func main() { var arr1 [5]int = [5]int{} arr1[1] = 99 var arr2 = [4]int{} // paintln 只能輸出簡單類型 //println(arr1) fmt.Println(arr1) // 不同的類型不能比較 //invalid operation: arr1 == arr2 (mismatched types [5]int and [4]int) // if arr1 == arr2 { // fmt.Println("arr1==arr2") // } //指向數組的指針 var arr3 = new([3]int) fmt.Println(&arr2, arr3) // 由編譯器推斷數組大小 arr4 := [...]int{1, 2, 3, 4, 5, 6, 10: 9} fmt.Println(arr4, len(arr4)) // 值類型 copy arr5 := arr4 fmt.Printf("%p,%p\n", &arr4[1], &arr5[1]) //arr6:=[2][3]int{} //多維數組 arr6 := [2][3]int{ {1, 2, 3}, {4, 5, 6}, } fmt.Println(arr6) } ``` ### range * 完整使用方式 `for k,v:=range arr{ /* do something*/}` * 索引方式 `for item:=range { /* do something*/}` * 值方式 `for _,v:=range arr{/* do something*/}` ``` package main import "fmt" func main() { var arr = [10]int{2, 3, 4, 5, 6, 7, 8, 9} for k,v:=range arr{ fmt.Println(k,v) //i:=0 //fmt.Printf("i:%p\n",&i) fmt.Printf("%p,%p\n",&k,&v) } println("oth") for item:=range arr{ fmt.Println(item) } for _,v:=range arr{ fmt.Println(v) } } ``` ![](https://box.kancloud.cn/3ce68d810665591af031a100e332e438_369x100.png) #### 課堂作業 選擇排序 ``` package main import "fmt" func main() { //選擇排序 arr := [...]int{1, 3, 2, 8, 5, 7, 9} fmt.Println(arr) for i := 0; i < len(arr)-1; i++ { for j := i + 1; j < len(arr); j++ { if arr[i] > arr[j] { // 交換兩個變量的值,不用定義第三個變量 arr[i], arr[j] = arr[j], arr[i] } } } fmt.Println(arr) } ``` ## 切片Slice * 其本身并不是數組,它指向底層的數組 ``` type slice struct{ len int cap int data point } ``` ![](https://box.kancloud.cn/e9e02517d67ebb089065440ef219d7cf_391x224.png) * 作為變長數組的替代方案,可以關聯底層數組的局部或全部 * **引用類型** * 可以直接創建或從底層數組獲取生成 * 如果多個`slice`指向相同底層數組,其中一個的值改變會影響全部 * 使用`len()`獲取元素個數,`cap()`獲取容量 ``` package main import "fmt" func main() { var arr = [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} // 一般方式 // var s1 []int =[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} var s1 = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println(s1) // 通過數組 // var s2 = arr[a:b]// a:b a<=x<b 0<x<len() // var s2 = arr[:] // var s2 = arr[0:len(arr)] var s2 = arr[0:3] //0,1,2 fmt.Println(s2) var s3 = arr[2:4] //2,3 fmt.Println(s3) // 引用 s2[2]=99 fmt.Println(s2) fmt.Println(s3) fmt.Println(len(s3),cap(s3)) } ``` ![](https://box.kancloud.cn/3b17569f85f25d7b5c3c31069eb88473_291x120.png) * 一般使用`make()`創建 ` make([]T, len, cap)` > 其中`cap`可以省略,則和`len`的值相同 * `len`表示存數的元素個數,`cap`表示容量 * `append` `copy` ``` package main import "fmt" func main() { // make創建 slice var s1 = make([]int, 2, 4) fmt.Println(s1, len(s1), cap(s1)) //[0 0] 2 4 // 省略cap則和len值相同 var s2 = make([]int, 2) fmt.Println(s2, len(s2), cap(s2)) //[0 0] 2 2 // append 可能會返回新的slice for i:=0;i<10;i++{ s1=append(s1,i,i+1) fmt.Printf("%p\n",s1)//fmt.Printf("%p\n",&s1) } // append 一個slice s1=append(s1,s2...) s3:=[]int{1,2,3,4,5} s4:=[]int{7,8,9} //copy(s3,s4) //fmt.Println(s3)//[7 8 9 4 5] copy(s4,s3) fmt.Println(s4)//[1 2 3] } ``` ![](https://box.kancloud.cn/7e9c8372ac234dee205e6caad7ed61c6_277x227.png) **注意** > reslice時索引以被slice的切片為準 > 索引不可以超過新slice的切片的`len()`值 > 索引越界不會導致底層數組的重新分配而是引發錯誤 >`append`只會在`slice`尾部追加元素 >可以將一個slice追加在另一個slice尾部 >如果最終長度未超過追加到slice的容量則返回原始slice >如果超過追加到的slice的容量則將重新分配數組并拷貝原始數據 >%p: `&sliceNmae`,`sliceName` ## map * 類似其它語言中的哈希表或者字典,以`key-value`形式存儲數據 * `key`必須是支持`==`或`!=`比較運算的類型,**不**可以是函數、`map`或`slice` * `map`使用`make()`創建,支持 `:=` 這種簡寫方式 * `make([keyType]valueType, cap)`,`cap`表示容量,可省略 * 超出容量時會自動擴容,但盡量提供一個合理的初始值 * 使用`len()`獲取元素個數 * 鍵值對不存在時自動添加,使用`delete()`刪除某鍵值對 * 使用`for range `對`map`和`slice`進行迭代操作 ``` package main import "fmt" func main() { // 創建 map //var m map[int]string = make(map[int]string, 4) //var m = make(map[int]string, 4) m := make(map[int]string, 4) fmt.Println(m,len(m)) m[2]="m2" m[10]="m10" fmt.Println(m) fmt.Println(m[1]) //沒有會返回零值 res,ok:=m[1] fmt.Println(res,ok) res,ok=m[2] fmt.Println(res,ok) // 刪除元素 delete (m,2) fmt.Println(m) m[1]="m1" m[2]="m2" m[3]=`m3` //遍歷 for k:=range m{ fmt.Print(k) fmt.Printf("\t%p\n",&k) } } ``` > rang 循環隨機 **注意** > 若對未初始化的map 不可進行賦值操作 ``` package main import "fmt" func main() { var m map[int]string fmt.Println(m[1]) delete(m,2) m[3]=`3` } ``` ![](https://box.kancloud.cn/60e3af3ffff46d7acc8b591bebd2461d_368x86.png) #### 課堂作業 根據在 for range 部分講解的知識,嘗試將類型為`map[int]string` 的鍵和值進行交換,變成類型`map[string]int` ``` package main import "fmt" func main() { //字面賦值 var m1 = map[int]string{ 1: "item1", 2: "item2", 3: "item3", 4: "item4", 5: "item5", 6: "item6", } fmt.Println(m1) var m2 = make(map[string]int) for k, v := range m1 { m2[v] = k } fmt.Println(m2) } ``` ## function * 定義函數使用關鍵字 func,且左大括號不能另起一行 * 函數也可以作為一種類型使用 * Go 函數 **不**支持嵌套、重載和默認參數 * 支持以下特性: > 無需聲明原型 不定長度變參 多返回值 命名返回值參數 匿名函數、閉包 ``` func funcName(參數列表 )(返回參數列){ //do something } ``` ``` // 多個同類型變量可簡寫,一個返回值可以省略括號 //func add(a int ,b int)(int){ //func add(a, b int) (int) { func add(a, b int) int { return a + b } ``` ``` package main import "fmt" func main() { // 函數作為一種類型 add := func(a, b int) { fmt.Println(a + b) } add(10, 20) f := newFunc(100) fmt.Println(f(10)) fmt.Println(f(100)) // 不定參數 params(1, 2, 3) params(1) params() // 多返回值 //a10, a100 := mutRtn(10) //fmt.Println(a10, a100) // 只接收想要的值 a10, _ := mutRtn(10) fmt.Println(a10) _, n := named(100) fmt.Println(n) // 匿名函數 func(x int) { fmt.Println("你不知道我的名字", x) }(10) } // 函數作為類型 func newFunc(x int) func(int) int { return func(t int) int { return x + t } } // 不定參數 func params(x ...int) { fmt.Println(x) } // 多返回值 func mutRtn(a int) (int, int) { return a * 10, a * 100 } // 命名返回值 func named(a int) (x int, y int) { x = 10 * a y = 20 * a return } ``` ## defer * 函數體執行結束后按照調用順序的**反順序**逐個執行 * 常用于資源清理、文件關閉、解鎖以及記錄時間等操作 * 支持匿名函數的調用 * 如果函數體內某個變量作為defer時匿名函數的參數,則在定義defer時即已經獲得了拷貝,否則則是引用某個變量的地址 ``` package main import "fmt" func main() { defer fmt.Println("hello defer") for i := 0; i < 5; i++ { func() { fmt.Println(i) }() defer func() { fmt.Println("defer:", i) }() //defer func(x int) { // fmt.Println("defer-:", x) //}(i) } } ``` * 通過與匿名函數配合可在return之后修改函數計算結果 ``` package main import "fmt" func main() { res := test(10) fmt.Println(res) res1 := test1(10) fmt.Println(res1) } func test(i int) int { defer func() { i++ }() return i * 10 } func test1(i int) (r int) { defer func() { r++ }() r = i * 10 return } ``` * 即使函數發生嚴重錯誤也會執行 * go 沒有異常機制,但有 panic/recover 模式來處理錯誤 * panic 可以在任何地方引發,但recover只有在defer調用的函數中有效 ``` package main import "fmt" func main() { // exit defer func() { if err := recover(); err != nil { fmt.Println(err) } }() panic("提前終止程序") } ``` ## struct * 結構體是一種聚合的數據類型,是由零個或多個任意類型的值聚合成的實體。每個值稱為結構體的成員 * 使用 `type <Name> struct{} `定義結構,名稱遵循可見性規則(大/小寫字母) * 支持指向自身的指針類型成員 * 支持匿名結構,可用作成員或定義成員變量 * 可以使用字面值對結構進行初始化 * 允許直接通過指針來讀寫結構成員 * 相同類型的成員可進行直接拷貝賦值 * 支持 == 與 !=比較運算符,但不支持 > 或 < * 支持匿名字段,本質上是定義了以某個類型名為名稱的字段 * 嵌入結構作為匿名字段看起來像繼承,但不是繼承 * 可以使用匿名字段指針 ## method * Go 中雖沒有class,但依舊有method * 通過顯示說明receiver來實現與某個類型的組合 * 只能為同一個包中的類型定義方法 * Receiver 可以是類型的值或者指針 * 不存在方法重載 * 可以使用值或指針來調用方法,編譯器會自動完成轉換 * 從某種意義上來說,方法是函數的語法糖,因為receiver其實就是 * 方法所接收的第1個參數(Method Value vs. Method Expression) * 如果外部結構和嵌入結構存在同名方法,則優先調用外部結構的方法 * 類型別名不會擁有底層類型所附帶的方法 * 方法可以調用結構中的非公開字段 ## interface * 接口是一個或多個方法簽名的集合 * 只要某個類型擁有該接口的所有方法簽名,即算實現該接口,無需顯示聲明實現了哪個接口 * 接口只有方法聲明,沒有實現,沒有數據字段 * 接口可以匿名嵌入其它接口,或嵌入到結構中 * 將對象賦值給接口時,會發生拷貝,而接口內部存儲的是指向這個復制品的指針,既無法修改復制品的狀態,也無法獲取指針 * 只有當接口存儲的類型和對象都為nil時,接口才等于nil * 接口調用不會做receiver的自動轉換 * 接口同樣支持匿名字段方法 * 接口也可實現類似OOP中的多態 * 空接口可以作為任何類型數據的容器 ## 更多 ### 類型斷言 * 通過類型斷言的`valur,ok`可以判斷接口中的數據類型 * 使用`type switch`則可針對空接口進行比較全面的類型判斷 ### 反射reflection * 反射使用 TypeOf 和 ValueOf 函數從接口中獲取目標對象信息 * 反射會將匿名字段作為獨立字段(匿名字段本質) * interface.data 是 settable即 pointer-interface則可利用反射修改對象狀態 * 通過反射可以“動態”調用方法 ### 并發 * 并發不是并行,并發主要由切換時間片來實現“同時”運行,并行則是直接利用多核實現多線程的運行 ## Channel * Channel 是 goroutine 溝通的橋梁,大都是阻塞同步的 * 通過 make 創建,close 關閉 * Channel 是引用類型 * 可以使用 for range 來迭代不斷操作 channel * 可以設置單向或雙向通道 * 可以設置緩存大小,在未被填滿前不會發生阻塞 ## Select * 可處理一個或多個 channel 的發送與接收 * 同時有多個可用的 channel時按隨機順序處理 * 可用空的 select 來阻塞 main 函數 * 可設置超時
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看