起源:學習 golang 筆記,看到 @Summer 的刻意練習、每日精進後,收益匪淺。程式設計就是需要刻意練習。堅持用此方法把 golang 看完。
書寫思路說明:對比 php,理解 Go 的特性,然後程式碼示例加深理解,並進行刻意的練習達到精進
Go 基礎
流程控制和函式
Go 中流程控制有三大類:條件判斷、迴圈控制、無條件跳轉
- if
- goto
- for
- switch
if
- 不需要
()
- 允許宣告變數「作用域只在條件邏輯內」
if a > b {
//
} else {
//
}
// 宣告變數
if x := computedValue(); x > 10 {
fmt.Println("x is greater than 10")
} else {
fmt.Println("x is less than 10")
}
// 多個條件
if a > 4 {
//
} else if a < 5 {
//
} else {
//
}
goto
跳轉到必須在當前函式定義的標籤
func myFunc() {
i := 0
Hear: // 這行的第一個詞,以冒號結束作為標籤
fmt.Println(i)
i++
goto Hear // 跳轉到 Hear 去「大小寫敏感」
}
for
go 中的 for 的三大用處
- 迴圈讀取資料
map
slice
= php 的 foreach - while 來控制邏輯 = php 的 while
- 迭代操作 = php 的 for
// foreach
for k, v := range map {
fmt.Println("map's key is ", k)
fmt.Println("map's value is ", v)
}
//由於 Go 支援 “多值返回”, 而對於“宣告而未被呼叫”的變數, 編譯器會報錯, 在這種情況下, 可以使用 _ 來丟棄不需要的返回值
for _, v := range map {
//
}
// while
sum := 1
for sum < 100 {
sum += sum
}
// for
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
switch
與 Php 比較
- case 的資料型別必須一致
- 表示式不必是常量或者整數,可以沒有表示式就找 true
- 自帶 break
- 支援多值聚合在一個 case 裡面
fallthrough
強制執行下一個 casecase
裡面不能有重複條件
i := 10
switch i {
case 10:
fmt.Println("i match 10")
fallthrough // 強制執行下一個 case
case i*2 - 10:
fmt.Println("表示式")
fallthrough
case 1, 2, 3: // 不能有重複條件 如果有 10 就會報錯
fmt.Println("多值聚合 i is 1 2 or 10")
fallthrough
case i == 10:
fmt.Println("bool 型別會報錯")
fallthrough
case 4:
fmt.Println("預設就有 break 的")
default:
fmt.Println("default")
}
函式
與 Php 不一樣的地方
- 關鍵字 func
- 引數 & 返回值需要指定型別
name type
- 多返回值
- 變參
// 多返回值1 引數相同型別可以簡寫
func sumAndProduct(a, b int) (int, int) {
return a + b, a * b
}
// 多返回值2
func sumAndProduct(a int, b int) (sum int, product int) {
sum = a + b
product = a * b
return
}
// 變參
func myfunc(arg ...int) {
for _, n := range arg { // arg 是一個int 的 slice
}
}
傳值與傳指標
PHP 一樣,傳值是傳值的 copy, & 傳地址。\
不同的是:\
channel,slice,map這三種型別的實現機制類似指標,所以可以直接傳遞,而不用取地址後傳遞指標
defer
Php 中沒有
作用:defer 後指定的函式會在函式退出前呼叫。多個 defer 呼叫順序後進後出「棧」
func ReadWrite() bool {
file.Open("file")
defer file.close() // 函式退出前這裡會被呼叫執行
if FailureX {
return false
}
return true
}
函式作為值型別
函式當做值來傳遞
- 宣告函式型別 = 定義資料型別
- 實現函式型別 = 實現資料型別
- 通過型別跟函式名 = 宣告一個變數
type testInt func(int) bool // 宣告型別
// 型別的實現
func isTwo(integer int) bool {
if (integer % 2) {
return true
}
return false
}
// 型別的實現
func isFive(integer int) bool {
if (integer % 5) {
return true
}
return false
}
// 宣告引數函式型別
func filter(slice []int, f testInt) []int {
var result = []int
for _, value := range slice {
if f(value) {
result = append(result, value)
}
}
return result
}
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println("slice = ", slice)
two := filter(slice, isTwo)
five := filter(slice, isFive)
fmt.Println("倍 2 整除的:", two)
fmt.Println("被 5 整除的:", five)
}
Panic 和 Recover
Go 沒有 try catch
\
用的 Panic
Recover
- Panic 中斷流程,並退出,延時函式繼續執行
- Recover 可以捕獲 Panic 中的引數
main 函式和 init 函式
引用圖片
import
與 PHP 對比 \
類似於 include
require
- 絕對路徑 相對於
GOROOT
目錄 - 相對路徑跟 PHP 一樣,但不推薦使用
.
操作- 別名操作:顧名思義
_
操作:不匯入包而是呼叫包的init()
// . 操作 可以省略字首的包名
import (
. "fmt"
)
fmt.Println("hello world") 可以省略的寫成 Println("hello world")
// 別名
import f "fmt"
f.Println("hello world")