Go xmas2020 全英課程 00-03 學習筆記
課程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)
主講老師 Matt Holiday
00-02-Hello Example
目錄結構
L:.
│ main.go
│
└───hello
hello.go
hello_test.go
- main.go 是主程式入口
- hello.go 是 hello 模組
- hello_test.go 用於單元測試 hello 模組
不一樣的Hello World
hello.go
package hello import ( "strings" ) func Say(names []string) string { if len(names) == 0 { names = []string{"world"} } return "Hello, " + strings.Join(names, ", ") + "!" }
傳入引數是一個字串切片,當切片長度為 0 時,自動給定一個長度為 1 的切片。
然後呼叫 strings.Join
方法將字串切片各個元素根據間隔符 ,
合併,在進行 + 運算子後返回完整字串。
巧妙的單元測試
hello_test.go
package hello import "testing" func TestSayHello(t *testing.T) { subtests := []struct { items []string result string }{ { result: "Hello, world!", }, { items: []string{"Matt"}, result: "Hello, Matt!", }, { items: []string{"Matt", "Anne"}, result: "Hello, Matt, Anne!", }, } for _, st := range subtests { if s := Say(st.items); s != st.result { t.Errorf("wanted %s (%v) | got %s", st.result, st.items, s) } } }
subtests
是一個匿名結構體的切片,我們可以在第二個花括號定義切片元素。
將引數與結果放在一起,for迴圈 subtests
進行多個單元測試,如果與預期不符就通過 t.Errorf
報錯
因為 Say
方法在 Hello.go
中首字母大寫宣告,所以為 Public
公開,外界可用
傳入os.Args切片
main.go
package main import ( "Work/Work/Study/Matt/2_cmd/hello" "fmt" "os" ) func main() { fmt.Println("Hello,", hello.Say(os.Args[1:])) }
匯入了hello包,通過 包名.方法名 呼叫(可以給包名起別名),因為 Say
函式需要傳入一個字串切片,我們不能直接傳入 os.Args[1]
否則是一個字串變數,巧妙的是可以用切片擷取 os.Args[1:]
的方式獲取一整個切片。
os.Args[n]
通常是執行go程式時新增的多餘引數,os.Args[0]
是程式的絕對路徑。
go run main.go cat dog
os.Args[0] 輸出 C:/xxx/xxx/xxx/main.go
os.Args[1] 輸出 cat
os.Args[2] 輸出 dog
go mod init
go mod init hello
用於在當前根目錄下生成 go.mod 檔案,可以 ignore GOPATH,可用於在任何目錄下的程式碼編寫。go 會自動做處理。
03-Basic Types
變數型別與直譯器
先看右圖,在 python 中,a並不是計算機實際意義上的數字,a是在直譯器中表示或偽裝的數字,使用C編寫的直譯器將使用底層硬體來做實際的數學運算,把這些東西編成二進位制數字。所以在python中雖然a=2,但計算機並不能立刻知道。
來看左圖,a純粹是機器中記憶體位置的地址,沒有直譯器,沒有jvm。這就是go的效能優勢,go編譯器直接生成機器程式碼,操作要快很多。
a:=2 在64位系統上,預設 64位 int
不要用內建浮點型別表示金錢
嘗試使用內建浮點型別來表示金錢是一種不好的做法,幾乎所有語言都是如此。浮點數實際上是為了科學計算。
使用內建浮點數表示金錢會有表示錯誤(精確度問題),缺少邏輯(100美分三次分割問題)
變數宣告方式
特殊型別
go 中布林值跟數字雙方是獨立的,不能互相轉換和比較。
變數初始化
如果不希望初始化最好使用 var 宣告變數,如果需要初始化使用短宣告語法
常量定義
go 限制常量為 數字,字串,布林值 型別。
型別轉換
package main
import "fmt"
func main() {
a := 2
b := 3.1
fmt.Printf("a: %8T %v\n", a, a)
fmt.Printf("b: %8T %[1]v\n", b) // ^ [1] 是Printf方法第二個引數
a = int(b) // ^ go 是一門嚴格的語言,需要進行顯式型別轉換
fmt.Printf("a: %8T %[1]v\n", a)
b = float64(a)
fmt.Printf("b: %8T %[1]v\n", b)
}
求平均值、標準流
package main
import (
"fmt"
"os"
)
func main() {
var sum float64
var n int
for {
var val float64
if _, err := fmt.Fscanln(os.Stdin, &val); err != nil {
fmt.Println(err)
break
} else {
sum += val
n++
}
}
if n == 0 {
fmt.Fprintln(os.Stderr, "no values") // ^ 需要告訴在哪個輸出流上列印
os.Exit(-1)
}
fmt.Println("The average is", sum/float64(n)) // ^ go沒有自動轉換,需要強制轉換
}
_, err := fmt.Fscanln(os.Stdin, &val)
用於從標準輸入流獲取輸入的行資料,並進行轉換,轉換失敗會將錯誤返回給 err,否則 err 為 nil
fmt.Fprintln(os.Stderr, "no values")
與 Println
差不多,只是需要告訴在哪個輸出流上列印