1. 程式人生 > 其它 >Go xmas2020 全英課程 00-03 學習筆記

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

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 差不多,只是需要告訴在哪個輸出流上列印