Go學習筆記一

變量、類型和關鍵字

完整的整數類型列表(符號和無符號)是

int8int16int32int64byteuint8uint16uint32uint64

混合用這些類型向變量賦值會引起編譯器錯誤,例如下面的代碼:

package main

func main() {
    var a int   //← 通用整數類型
    var b int32 //← 32 位整數類型
    a = 15
    b = a + a //← 混合這些類型是非法的 
              //cannot use a + a (type int) as type int32 in assignment
    println(b)
    b = b + 5 //← 5 是一個(未定義類型的)常量,所以這沒問題
    println(b)
}

字符串

字符串在 Go 中是 UTF-8 的由雙引號(”)包裹的字符序列。如果你使用單引號(’)則
表示一個字符(UTF-8 編碼)——這種在 Go 中 不是 string。
一旦給變量賦值,字符串就不能修改了:在 Go 中字符串是不可變的。從 C 來的用戶,
下面的情況在 Go 中是非法的。

var s string = "hello"
s[0] = 'c' //← 修改第一個字符爲 ’c’ ,這會報錯

在 Go 中實現這個,需要下面的方法:

package main 

import "fmt"

func main() {
    var s = "hello"
    var c = [] rune (s)//轉換 s 爲 rune 數組

    c[0] = 'c'//修改第一個字符爲 ’c’

    var s2 = string (c)//創建 新的 字符串 s2 保存修改;

    fmt.Printf("%s\n", s2)

}

多行字符串

基於分號的置入,你需要小心使用多行字符串。如果這樣寫:

s := "Starting part"
+ "Ending part"

會被轉換爲:

s := "Starting part" ;
+ "Ending part" ;

這是錯誤的語法,應當這樣寫:

//正確的方式一:
s := "Starting part" +
"Ending part"

正確的方式二:
Go 就不會在錯誤的地方插入分號。另一種方式是使用反引號 ` 作爲 原始 字符串符號:

//正確的方式二:
s := `Starting part
Ending part`

fmt.Printf("Value is: %v", s)//Printf() 的 %v 參數含義是用默格式打印這個值  

控制結構

在 Go 中只有很少的幾個控制結構例如這裏沒有 do 或者 while 循環,只有
for 。有(靈活的) switch 語句和 if ,而 switch 接受像 for 那樣可選的初始化語句。還有叫做類型選擇和多路通訊轉接器的 select,語法有所不同(同 C 相比):
無需圓括號,而語句體必須 總是 包含在大括號內。

if

if x > 0 { //← { 是強制的
    return y
} else {
    return x
}
//===============
//下面的語法在 Go 中是非法的:
if err ! = nil
{    // ← 必須同 if 在同一行
    return err
}
//if 和 switch 接受初始化語句,通常用於設置一個(局部)變量。
if err := Chmod(0664) ; err ! = nil { //← nil 與 C 的 NULL 類似
    fmt.Printf(err) //← err 的作用域被限定在 if 內
    return err
}

goto

Go 有 goto 語句——明智的使用它。用 goto 跳轉到一定是當前函數內定義的標籤。例如假設這樣一個循環:

package main 

func main() {
    myfunc()

}
func myfunc() {
    i := 0
Here:   // ← 這行的第一個詞,以分號結束作爲標籤,標籤大小寫敏感
    println(i)
    i++
    if i > 10 { //打印1  到  10 ,這裏不加條件會是無限循環
        return 
    }
    goto Here// ← 跳轉
}

for循環

Go 的 for 循環有三種形式,只有其中的一種使用分號。

for init ; condition ; post { } //← 和 C 的 for 一樣
for condition { } //← 和 while 一樣
for { } //← 死循環
//由於 Go 沒有逗號表達式,而 ++ 和 – 是語句而不是表達式,如果你想在 for 中
//執行多個變量,應當使用 平行賦值。
// Reverse a
for i, j := 0, len (a)-1 ; i < j ; i, j = i+1, j-1 {
    a[i], a[j] = a[j], a[i] //← 平行賦值
}

break 和 continue
循環嵌套循環時,可以在 break 後指定標籤。用標籤決定 哪個 循環被終止:

package main 

func main() {
    myfunc()

}
func myfunc() {
    for j := 0 ; j < 5 ; j++ {
        for i := 0 ; i < 10 ; i++ {
            if i > 2 {
                break  //← 現在終止的是 j 循環,而不是 i 的那個
            }
            println(i)
        }
        println(j)
    }
}
//continue
package main 

func main() {

    for i := 0 ; i < 10 ; i++ {
        if i > 5 {
            continue //← 跳過循環中所有的代碼 println(i)
        }
        println(i)
    }
}

range迭代器

range 是個迭代器,當被調用的時候,從它循環的內容中返回一個鍵值對

package main 
import "fmt"
func main() {

    list := [] string { "a", "b", "c", "d", "e", "f" }

    for k, v := range list {

        // 對 k 和 v 做想做的事情
        fmt.Printf("list[%d] = %s\n",k,v)
    }
}
// list[0] = a
// list[1] = b
// list[2] = c
// list[3] = d
// list[4] = e
// list[5] = f

switch

可以使用 fallthrough 使其匹配失敗後自動向下嘗試。
沒有 fallthrough :

switch i {
    case 0: // 空的 case 體
    case 1:
        f() // 當 i == 0 時, f 不會被調用!
}

而這樣:

switch i {
    case 0: fallthrough
    case 1:
        f() // 當 i == 0 時, f 會被調用!
}

用 default 可以指定當其他所有分支都不匹配的時候的行爲。

switch i {
    case 0:
    case 1:
        f()
    default :
        g() // 當 i 不等於 0 或 1 時調用
}

分支可以使用逗號分隔的列表。

package main 
// import "fmt"
func main() {
    println(shouldEscape('?'))  //true
}

func shouldEscape(c byte ) bool {
    switch c {
        case ' ', '?', '&', '=', '#', '+':// ← , as ”or”
        return true
    }
    return false
}

內建函數

 //Go 中的預定義函數
close new panic complex
delete make recover real
len append print imag
cap copy println

可以使用命令查看函數文檔

go doc builtin // 獲得關於內建類型和函數的在線文檔。

查看某個函數文檔

//獲得copy的文檔  go doc builtin copy

這裏寫圖片描述

close
//用於 channel 通訊。使用它來關閉 channel,
delete
//用於在 map 中刪除實例。
lencap
//可用於不同的類型, len 用於返回字符串、slice 和數組的長度。
new
//用於各種類型的內存分配。
make
//用於內建類型(map、slice 和 channel)的內存分配。
copy
//用於複製 slice。
append
//用於追加 slice。
panicrecover
//用於 異常 處理機制。

printprintln
//是底層打印函數,可以在不引入 fmt 包的情況下使用。它們主要用於調試。
complexrealimag
//全部用於處理 複數。

array、slices 和 map

array

array 由 [n]<type> 定義,n 標示 array 的長度,而 <type> 標示希望存儲的內容的類型。對 array 的元素賦值或索引是由方括號完成的:

package main 
import "fmt"
func main() {
    // var arr = [10] int 這樣的數組類型有固定的大小。大小是類型的一部分 。由於不同的大小是不同的類型,因此不能改變大小
    var arr [10] int
    arr[0] = 42
    arr[1] = 13
    fmt.Printf("The first element is %d\n", arr[0]) 
}

var arr = [10] int 這樣的數組類型有固定的大小。大小是類型的一部分 。由於不同的大小是不同的類型,因此不能改變大小。數組同樣是值類型的:將一個數組賦值給另一個數組,會 複製 所有的元素。尤其是當向函數內傳遞一個數組的時候,它會獲得一個數組的副本,而不是數組的指針

可以像這樣聲明一個數組:var a [3] int,如果不使用零來初始化它,則用複合聲明:
a := [3] int{ 1, 2, 3 } 也可以簡寫爲 a := [...] int{ 1, 2, 3 },Go 會自動統計元素的個數。

//多維數組
a := [3][2] int { [2] int { 1,2 } , [2] int { 3,4 } , [2] int { 5,6 } }

slice

slice 是一個 指向 array 的指針,這是其與 array 不同的地方;slice 是引用
類型,這意味着當賦值某個 slice 到另外一個變量,兩個引用會指向同一個 array。

sl := make ([] int , 10)
//錯誤的示例,如果要擴展slice需要使用append和copy
package main
func main() {
    var array [100] int //← Create array, index from 0 to 99
    slice := array[0:99] //← Create slice, index from 0 to 98
    slice[98] = 'a'// ← OK
    slice[99] = 'a'// ← Error: ”throw: index out of range”
}

使用append擴展slice

package main
import "fmt"
func main() {

    s0 := [] int { 0, 0 }

    s1 := append (s0, 2)//追加一個元素, s1 == []int{0, 0, 2} ;

    fmt.Printf("%v\n",s1)

    s2 := append (s1, 3, 5, 7)//追加多個元素, s2 == []int{0, 0, 2, 3, 5, 7} ;

    fmt.Printf("%v\n",s2)
    //...可變長參數  http://studygolang.com/articles/1965
    s3 := append (s2, s0...)//追加一個 slice, s3 == []int{0, 0, 2, 3, 5, 7, 0, 0} 。注意這三個點!

    fmt.Printf("%v\n",s3)
}
// [0 0 2]
// [0 0 2 3 5 7]
// [0 0 2 3 5 7 0 0]

copy的使用

package main
import "fmt"
func main() {

    var a = [...] int { 0, 1, 2, 3, 4, 5, 6, 7 }
    var s = make ([] int , 6)
    n1 := copy (s, a[0:])// ← n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
    fmt.Printf("%v\n",s)
    fmt.Printf("%v\n",n1)
    //copy返回拷貝的元素個數
    n2 := copy (s, s[2:])// ← n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
    fmt.Printf("%v\n",s)    
    fmt.Printf("%v\n",n2)
}

map

一般定義 map 的方法是: map[<from type>]<to type>

package main
import "fmt"
func main() {

    monthdays := map [ string ] int {
    "Jan": 31, "Feb": 28, "Mar": 31,
    "Apr": 30, "May": 31, "Jun": 30,
    "Jul": 31, "Aug": 31, "Sep": 30,
    "Oct": 31, "Nov": 30, "Dec": 31,// ← 逗號是必須的
    }
    // monthdays := make ( map[ string ] int )//當只需要聲明一個 map 的時候,使用 make 的形式
    fmt.Printf("%d\n", monthdays["Dec"])//打印出 12 月的天數
    year := 0
    for _, days := range monthdays { //← 鍵沒有使用,因此用 _, days
        year += days
    }
    fmt.Printf("Numbers of days in a year: %d\n", year)
    //向 map 增加元素,可以這樣做:
    monthdays["Undecim"] = 30 //← 添加一個月
    monthdays["Feb"] = 29 //← 閏年時重寫這個元素
    //檢查元素是否存在的兩種方式
    //var value int
    var present bool
    //value, present = monthdays["Jan"]
    _, present = monthdays["Jan"] //← 如果存在, present 則有值 true
    println(present)
    //← 或者更接近 Go 的方式
    //v, ok := monthdays["Jan"]
    _, ok := monthdays["Jan"]// ← “逗號 ok ”形式    
    println(ok)
    //也可以從 map 中移除元素:
    delete(monthdays, "Mar") //← 刪除 ”Mar” 吧
}


參考文章:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章