Go學習筆記(1): HelloWorld

在之前寫到今年的計劃 當中,我就說到我想要學Go 語言。同時我自己也買了一本有關於Go 的書:深入淺出Go , 希望藉此督促自己有個比較完整性的學習……

以下是我讀這本書以及學習的心得與筆記,可能有點無聊,高手請跳過、不過如果有看到錯的也請不吝指正!

首先,你要先去安裝好Go…….

程式組成

Go 語言的組成通常有三個部分:

  1. 套件子句(package main)
  2. import 相關陳述句 (import "fmt")
  3. 主要的程式碼 (func main(){......})

Hello World 程式!

讓我們先建立一個名為hello.go 的檔案… 然後在裡面寫這些東西…

1package main
2import "fmt"
3
4func main(){
5	fmt.Println("Hello World")
6	// 這裡請務必使用 " 否則很容易跳出 invalid character literal (more than one character) 的問題
7}

接下來讓我們對這個檔案做go run hello.go 就可以看到 Hello World 的字眼啦!

Go 的資料型態類別

  1. 字串:用雙引號所框起來的任意數量字元
  2. 符文(runes) : 用單引號所匡著的單一字元, ex. ‘A’ , ‘B’
  3. boolean (bool)
  4. numbers
    1. float32 , float64
    2. int8 ,int16 ,int32 ,int64
    3. uint
    4. uint8 , uint16 ,uint32 ,uint64
  5. byte (檔案專用)

tips: 可以透過 reflect 這個套件裡面的TypeOf 方法得知資料的型別

 1package main
 2
 3import (
 4  "fmt"
 5  "reflect"
 6)
 7
 8func main() {
 9	fmt.Println(reflect.TypeOf("Hello World")) //string
10	fmt.Println(reflect.TypeOf(true)) // bool
11}

宣告變數

  • var q int
  • var q int = 4
  • p,q = 4,5 (居然有像Python 一樣的多重賦值!)
  • p :=4 (快速寫法, 連型別都不用!)

命名規則

  1. 開頭必須是字母
  2. 如果開頭字母是大寫,表示他是可以被匯出的

陣列

在Go 裡面要宣告陣列,請用以下的code 得形式

 1// 第一種
 2var todos [2]string
 3todos[0]= "learning go !"
 4todos[1]= "use go to write an app"
 5// 第二種
 6var grades [3]int = [3]int{90,98,93}
 7
 8// 第三種
 9heights := [3]int{90,98,93}
10
11// go 裡面的foreach , 陣列/map資料型態都適用!
12for index,note := range notes{
13    fmt.Println(index,note)
14}

切片

這是我在深入淺出Go 這本書裡面的某一個章節,他裡面寫道Go 宣告切片就像是宣告陣列變數, 只是不需要指定大小!for example:

1var mySlice []int
2mySlice = make([]int,7) // 設定七個數字的切片
3fmt.Printf("%v",mySlice) //[0 0 0 0 0 0 0]
4// 增加
5newSlice := append(mySlice, 5,9) // 回傳新的, 增加完的切片
6fmt.Printf("%v",newSlice) //[0 0 0 0 0 0 0 5 9]

錯誤處理

說真的,最近在學著Go 都覺得他的語言調性和其他語言差很多,像是if/for 的區域範圍變數無法用在if/for 後面(但之前的宣告可以使用)、陣列的宣告是很獨樹一幟的他也不像傳統程式語言那種try…catch 的敘述,而是你要分成你自己去處理或者直接error 中斷給你看這樣

像是這樣, 你必須用參數去接下可能會error 的地方,然後用if 去判斷, 控制壞掉之後的流程這樣。詳細你可以參考此連結:

https://michaelchen.tech/golang-programming/error-handling/

或者你也可以使用 panic 這個關鍵字 或 用 recover 這個關鍵字讓他從panic 的狀態中恢復, 另外也筆記一下 defer 可以添加到任何地方,用來暫緩該調用直到目前程式結束

詳細可以參考此網址:

https://openhome.cc/Gossip/Go/DeferPanicRecover.html

1file, err := os.Open("file.txt")         
2 if err != nil {                         
3     ....         
4 }  
5defer file.Close()                                    

Maps

有點像是Python 裡的 dictionary , 或者 php 的 association array……

 1var myMap map[string]float64 // 宣告出以字串型態為index, float64型態的值
 2myMap = make(map[string]float64)
 3
 4// 又或者可以做更簡單的宣告
 5myMap := make(map[string]float64)
 6
 7
 8// 如何把東西放進去...
 9myMap["Jimmy"] = 12.4
10myMap["Bob"] = 15.3
11
12// 如果已經知道要建立怎麼樣的map
13myMap := map[string]float64{"Jimmy":12.4 , "Bob":15.3}
14
15// 另外如果取得一個沒有被指派的index 會根據型態而回傳不同的值
16// 數字:0
17// 字串:""
18// * 如果沒有make 它則會是一個nil 的 map, 而nil 的 map 無法被指派值
19// 可以視情況給予第二個參數,好讓map 可以判斷是否有這個index
20var value string
21var exist bool
22value , exist = myMap["Andy"] // return 0, false
23
24// 移除
25myMap["Jim"] = 999
26delete(myMap,"Jim")

結構 struct

 1var myStruct struct {
 2    name string
 3    grade int
 4}
 5myStruct.name = "Jimmy"
 6myStruct.grade = 10
 7
 8// 自訂型別, 前面使用type 這個關鍵字
 9type myStruct struct {
10    name string
11    grade int
12}
13
14// 自訂型別也能加入method
15func (m myStruct) hello() string {
16    return "hello"
17}
18// 自訂型別也可以加入getter /setter 封裝裡面的資料結構
19func (m *myStruct) SetName(name string){
20   m.name = name
21}
22
23func (m *myStruct) Name() string {
24   return m.name
25}
26
27
28// 透過指標存取結構
29func applyDiscount(s *subscriber){
30    s.rate = 4.99
31}
32
33func main() {
34    var s subscriber
35    applyDiscount(&s)
36}

結構裡面可以有另外一個結構,而Go另外還支援了匿名結構欄位,不用特別設定名稱也可以直接帶進去結構裡

1type Employee struct {
2    Name string
3    Salary float64
4    Address
5}
6
7type Address struct {
8     ......
9}

介面 interface

在 Go 裡面也有介面的概念,定義某些特定得值與某些特定的行為。

1type myInterface interface {
2   methodOne()
3   methodTwo(float64)
4   method() string
5}

測試

在Go 裡面,我們可以使用testing 這個套件,首先是要讓我們在同樣的套件底下建立一個_test 結尾的Go 檔案,話不多說,show you some code !

1func TestFunction(t *testing.T){
2    ......()
3    if ...()
4    t.Errorf("......")
5}

function programming

在Go 裡面, function 本身也能夠被視為變數, 型別處理,像是

 1// 此範例來自深入淺出Go p.439
 2func callFunction(passedFunction func()){
 3  passedFunction()
 4}
 5
 6func callTwice(passedFunction func()){
 7  passedFunction()
 8  passedFunction()
 9}
10
11func callWithArguments(passedFunction func(string, bool)){
12  passedFunction("this sentence is",false)
13}
14
15func printReturnValue(passedFunction func() string){
16  fmt.Println(passedfunction())
17}
18
19func functionA(){
20  fmt.Println("function called")
21}
22
23func functionB() string{
24    fmt.Println("function called")
25    return "Returning from function"
26}
27
28func functionC(a string , b bool){
29    fmt.Println("function called")
30    fmt.Println(a,b)
31}
32
33func sayHi(){
34  fmt.Println("Hi")
35}
36
37func main(){
38    var myFunction = func()
39    myFunction = sayHi
40    myFunction()
41
42    callFunction(functionA)
43    callTwice(functionA)
44    callWithArguments(functionC)
45    printReturnValue(functionB)
46}

相關指令

  • go build :編譯成二進位
  • go run :編譯及執行
  • go fmt :格式化原始碼
  • go version :go 的版本
  • go test : 測試go
  • go doc : 說明文件

小君曰:來學Go 啦, go !


談Python: Lambda, Map , Filter 及 Reduce
Go學習筆記(2): make a game