- Defer 執行順序
- Range & Foreach
- golang 執行的隨機性和閉包
- golang 的組合繼承
- Select 隨機性
- Defer 執行順序
- make 預設值和 append
- map 執行緒安全
- chan緩存池
- interface 實作方式
- interface內部結構
- Type Assertion
- Return Value Naming
- defer和函式返回值
- new & make
- slice append
- Struct Compare
- Return Type
- iota
- Short variable declarations
- Const Address
- goto 位置
- Type Alias
- if 變數作用域
Defer 執行順序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
https://play.golang.org/p/Zpbiau9RuGm
- defer 採用後進先出(Last In First Out (LIFO))
- panic 需等所有的 defer 結束後才會執行
Range & Foreach
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
https://play.golang.org/p/ocNj5lp0W0_4
- range 是用 copy 的方式,因此每個 key 都指向同一個 point,最後的值就會是最後一個指向的 value
解決方式,改用 index 的方式
for i := 0; i < len(stus); i++ { m[stus[i].Name] = &stus[i] } for k, v := range m { fmt.Println(k, "=>", v.Name) } for i, _ := range stus { m[stus[i].Name] = &stus[i] } for k, v := range m { fmt.Println(k, "=>", v.Name) }
golang 執行的隨機性和閉包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
https://play.golang.org/p/EzCWf8r1wnt
- 第一個 func 沒有將 i 帶入,取得的 i 是 for 外部的 i,並且 i 會一直加 1 直到 10,因此最後輸出的 A 全部都是 10
- 第二個 func 則是每次都會帶入 i,每個 i 都會做 copy 帶入 func,因此外部的 ++ 不會影響到
golang 的組合繼承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
https://play.golang.org/p/eSGvASIBn5K
- 透過組合的方式,來實現 OO 的繼承,當 struct 有
anonymous struct field
,就會被當成promoted fields
,簡單的來說原本 people 的方法(必須是匿名)就可以直接被 teacher 給調用 - 當呼叫了 showA() 裡面在 call showB() 時,此時 People 類型並不知道自己會被什麼類型組合,因此無法去使用未知的組合者 Teacher 類型的 func
Select隨機性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
https://play.golang.org/p/ntESh6QYaYT
- select 擁有隨機性,因此都有可能觸發
- 當只要有個 case 可以 return 就可以立即執行
- 都能 return 則隨機
- 都不行則跑 default
Defer 執行順序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
https://play.golang.org/p/BrhIs-_chN_y
- defer 採用後進先出(Last In First Out (LIFO))
make 預設值和 append
1 2 3 4 5 6 7 8 9 |
|
https://play.golang.org/p/7VHcPYjenWw
- make 初始化時,後面直有一個值的話,代表 len 和 cap,因此裡面預設就有 5 個 default 0,所以在 append 時,會再繼續加上去
map 執行緒安全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
https://play.golang.org/p/KwtbBryhP5x
- 在讀(Get)的時候,沒有加上 Lock,可能會導致
fatal error: concurrent map read and map write
- 更改為
go func (ua *UserAges) Get(name string) int { ua.Lock() defer ua.Unlock() if age, ok := ua.ages[name]; ok { return age } return -1 }
chan緩存池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
https://play.golang.org/p/2n2GBeo35Jo
- chan 不是 buffer chan 因此,會造成阻塞,並且顯示不了所有的 value,當 range 將第一個 “1” 放進 chan 後,再跑第二次要放進 “2” 時,必須等待第一個值被取出來,因此會停在那邊,但是當取出來後,就會繼續進行下面,導致直接結束
- 改用 buffer chan
go ch := make(chan interface{},len(set.s))
interface 實作方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
https://play.golang.org/p/u1qbY4CbVNQ
- 因為實作 interface 的是 pointer receiver,所以會造成 error
go var peo People = &Stduent{}
interface內部結構
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
https://play.golang.org/p/2nBU-dMwW6b
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
https://play.golang.org/p/lx6W61O66P
- golang 中的 interface 分兩種,但底層結構稍微不同,因此 data 指向了
nil
並不代表 interface 是nil
var in interface{}
type People interface { Show() }
- 第二個改成
var x interface{}
則為empty interface
- Go語言interface底層實現
- Go介面詳解
Type Assertion
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
https://play.golang.org/p/-OiFMCcYttw
- Type Assertion 只能用於 interface
Return Value Naming
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
https://play.golang.org/p/nH6KTCel6ns
- 只要有一個返回值有命名,全部就必須命名
- 如果兩個 type 一樣,則可以只寫一個
defer和函式返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
https://play.golang.org/p/HpOb3huRV-0
- defer 需要在 func 結束前執行
- func return 名字會在函式起始處被初始化為對應類型的零值並且作用域為整個函式
- DeferFunc1 - t 作用域為整個 func,因此 return 前會將 t 更改
- DeferFunc2 - t 作用域為裡面的 func,因此不影響外面的 t
- DeferFunc3 - t 作用域為整個 func,跟 Func 1 一樣
new & make
1 2 3 4 5 6 7 8 9 |
|
https://play.golang.org/p/CEwGhsmQfZx
- new 可以用來初始化泛型,並且返回儲存位址
- new 會自動用 zeroed value 來初始化型別
string
=> “”int
,float
=> 0channel
,func
,map
,slice
=>nil
- 必須改用 make([]int, 0), 初始化 slice (make 不會回傳指標)
- Go 語言中的 make 和 new
- golang 筆記:make 與 new 的差別
- Allocation with new
- Allocation with make
slice append
1 2 3 4 5 6 7 8 9 10 |
|
https://play.golang.org/p/xOWsWj0Evni
- append slice 必須加上
...
展開s2...
Struct Compare
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
https://play.golang.org/p/3cEX9aYtvsR
- struct 只能在相同類型才能做比較,順序也會有差
- 這樣也不能做比較
sn3 := struct { age int name string }{age: 11, name: "qq"}
- map 和 slice 則不可比較,如果要比較要用
reflect.DeepEqual
if reflect.DeepEqual(sm1, sm2) { fmt.Println("sm1 == sm2") }
Return Type
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
https://play.golang.org/p/noHSLgTvdEq
nil
可以用作interface
、function
、pointer
、map
、slice
和channel
的"空值"。
iota
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
https://play.golang.org/p/XwtR_I0fQdp
Short variable declarations
1 2 3 4 5 6 7 8 9 10 11 12 |
|
https://play.golang.org/p/AUfpBHZg-F4
:=
是聲明並賦值,並且系統自動推斷類型,必須放在 main function 裡面
Const Address
1 2 3 4 5 6 7 8 9 10 11 |
|
https://play.golang.org/p/dbK6-maWceJ
- 常量不同於變數的在運行期分配記憶體,常量通常會被編譯器在預處理階段直接展開,作為指令數據使用
- pointers - Find address of constant in go
goto 位置
1 2 3 4 5 6 7 8 9 10 11 12 |
|
https://play.golang.org/p/-0KuesWC3kM
- goto 必須放在 func 裡面
Type Alias
1 2 3 4 5 6 7 8 9 10 11 12 |
|
https://play.golang.org/p/ELp_QFf5-o2
- 基於一個類別型建立一個新類型,稱之為 defintion
- 基於一個類別型建立一個別名,稱之為 alias
- MyInt1 為稱之為 defintion,雖然底層類型為 int 類型,但是不能直接賦值,需要強轉
- MyInt2 稱之為 alias,可以直接賦值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
https://play.golang.org/p/2fsGAqTmUrH
i2.m1()
會 error,因為 m1() 是MyUser1
才有的 func,不是 User
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
https://play.golang.org/p/zwvjqUFLHax
- 重複會不知道該 call 哪一個導致 error (
ambiguous selector my.m1
),把其中一個拿掉就可以 work,或是改為my.T1.m1()
+my.T2.m1()
if 變數作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
https://play.golang.org/p/CvqxnzGSAG9
- if 的變數會遮罩函式作用域內的變數,導致裡面的 b 是新的 address
closure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
https://play.golang.org/p/8RL7gO5_4EF
funx
裡的 i 都是同一個,要不一樣要先 assign 到新的 valuego for i:=0;i<2 ;i++ { x:=i funs = append(funs, func() { println(&x,x) }) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
https://play.golang.org/p/5ReC78kUM3c
- 閉包引用相同變數