Go語法筆記
四種宣告語句
Go語言主要有四種類型的宣告語句:var, const, type 和 func, 分別對應變數, 常量, 型別和函式實體
物件的宣告 // 當前程式的包名(一個可執行程式只有一個 main 包) //一般建議package的名稱和目錄名保持一致 package main // 匯入其它包 // 缺少或未使用的包,程式都無法編譯通過 import "fmt" // 通過 const 關鍵字字來進行常量的定義 const number1 = 10 // 通過 var 關鍵字來宣告變數 var number2 = 20 // 陣列 var number3 = [5]int{1, 3, 5, 7, 9} // 集合 var number4 = map[string]int{ "Age1": 18, "Age2": 19, "Age2": 20, } // 一般型別宣告 type number5 int // 結構宣告 type number6 struct{} // 介面宣告 type number7 interface{} // 通過 func 關鍵字來進行函式的宣告 // 只有 package 名稱為 main 的包才可以包含 main 函式 func main() { fmt.Println("Hello World") }
操作符
比較操作符
go中型別
字串操作
變數和常量
命名規則
- 名字必須以一個字母或下劃線開頭, 後面可以跟任意數量的字母, 數字或下劃線
- 不允許使用某個關鍵字命名
- Go語言中有25個關鍵字, 關鍵字不能用於命名, 只能在特定語法結構中使用
- 根據首字母的大小寫來確定可以訪問的許可權; 首字母大寫, 可以被其他的包訪問; 首字母小寫, 則只能在
本包中使用
變數
var a int = 1 fmt.Println(a) //var可以宣告一個或多個變數 var b, c string = "a", "b" fmt.Println(b, c) //宣告為沒有相應初始化的變數是零值的(int的零值是0, string的零值是空) var d int fmt.Println(d) //Go將推斷初始化變數的 //(:=)簡短變數宣告一般用於區域性變數的宣告和初始化,var往往是用在需要先指定變數型別稍後再賦值的 //不過它有一個限制,那就是它只能用在函式內部;在函式外部使用則會無法編譯通過,所以一般用var方式 來定義全域性變數 e := true fmt.Println(e) //_(下劃線)是個特殊的變數名,任何賦予它的值都會被丟棄 _, f := 7, 8 fmt.Println(f)
常量
//const 可以定義一個或多個常量
const b, c = 1, 3
fmt.Println(b, c)
//表示式裡可以有常量, 但不能有變數
const d = 4 - b
fmt.Println(d)
const (
a int = iota
b
)
const (
a int = 1 << iota
b
)
條件判斷語句
if語句
1.條件表示式沒有括號
2.支援一個初始化表示式(可以是多變數初始化語句)
3.左大括號必須和條件語句同一行
if number := 7; number < 1 { fmt.Println(1) } else if number >= 1 && number <= 10 { fmt.Println(2) } else { fmt.Println(3) }
switch語句
switch中不需要break,因為預設不會向下貫穿執行
switch number1 := 3; number1 {
case 1:
//如希望繼續執行下一個case,可以使用fallthrough語句
fallthrough
fmt.Println(1)
case 3:
fmt.Println(3)
case 5:
fmt.Println(5)
}
for迴圈語句
支援3種形式
傳統格式:for init; condition; post {}
while迴圈:for condition {}
無限迴圈:for {}
//形式一:
for number1 := 1; number1 < 3; number1++ {
fmt.Printf("number1:%d\n", number1)
}
//形式二:
number2 := 1
for number2 < 3 {
fmt.Printf("number2:%d\n", number2)
number2++ //不能寫成 number2 = number2++(++ 與 -- 是作為語句而不是作為表示式)
}
//形式三: for沒有條件將無限迴圈;用break 退出迴圈
for {
fmt.Println("loop")
break
}
range遍歷
number := [5]string{"a", "b", "c", "d", "e"}
for k, v := range number {
fmt.Println(k, v)
}
語句跳轉goto,break,continue
1.支援函式內部 goto 跳轉, continue 跳出當前迴圈進入一下次迴圈,break 終止迴圈體
2.break 和 continue 都可以配合標籤,在多級巢狀迴圈間跳出.這和 goto 調整執行位置完全不同
3.通常建議往後 goto,避免死迴圈
for number := 1; number < 5; number++ {
if number == 3 {
break
}
fmt.Println("break:", number)
}
for number := 1; number < 5; number++ {
if number == 3 {
continue
}
fmt.Println("continue:", number)
}
lable1:
for {
for {
//配合標籤跳出最外層迴圈
//標籤名是大小寫敏感的
break lable1
}
}
fmt.Println("Hello World1")
goto lable2
fmt.Println("Hello World2")
lable2:
fmt.Println("Hello World3")
陣列、切片、集合、通道
陣列array
1.如果在陣列的長度位置出現的是“…”省略號,則表示陣列的長度是根據初始化值的個數來計算
2.陣列的長度必須是常量表達式,因為陣列的長度需要在編譯階段確定
number1 := [3]int{1, 2, 2: 3}
number2 := [3][4]int{
{1, 2, 3, 4},
{5, 6, 7, 8},
{0: 9, 1: 10, 2: 11, 3: 12},
}
number4 := [...]int{3, 1, 9, 6, 8}
由於陣列長度固定,所以不可新增,刪除,只能更新
切片slice
[]T,T為型別
1.make([]T, length長度, capacity容量)
2.一般使用make()建立 : 用len獲取切片長度, cap獲取切片容量
3.一個切片在未初始化之前預設為 nil,長度為 0
4.與陣列相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大
切片複製copy()
copy 函式copy從源slice的src中複製元素到目標dst,並且返回複製的元素的個數
number1 := []int{1, 2, 3, 4, 5}
number2 := []int{6, 7, 8}
number3 := copy(number1, number2)
fmt.Println(number1, number2, number3)
結果:
[6 7 8 4 5] [6 7 8] 3
追加append
number1 := []int{1, 2, 3}
fmt.Println(number1, len(number1), cap(number1))
number1 = append(number1, 4, 5)
fmt.Println(number1, len(number1), cap(number1)) //按初始容量成倍擴大
number3 := append(number1, number1...) //用省略號自動展開切片,以使用每個元素
fmt.Println(number3)
結果:
[1 2 3] 3 3
[1 2 3 4 5] 5 6
[1 2 3 4 5 1 2 3 4 5]
刪除
刪除下標是index的元素
slice = append(slice[ : index ] , slice[ index+1 : ])
刪除頭部元素
slice = slice[1:]
刪除尾部
slice = slice[:len(slice) -1]
遍歷slice
number := [5]string{"a", "b", "c", "d", "e"}
for k, v := range number {
fmt.Println(k, v)
}
集合map
map[T1]T2,T1為鍵的型別,T2為值的型別,鍵的型別必須是支援==或!=比較運算的型別
1.map的迭代順序是隨機的
2.若想按指定順序遍歷map,先將鍵取出放入一個slice,然後對鍵排序,按鍵序訪問map
number3 := map[int]string{1: "a", 2: "b", 3: "c", 4: "d", 5: "e"}
number4 := make([]int, len(number3))
i := 0
for k, v := range number3 {
fmt.Println(k, v)
number4[i] = k
i++
}
刪除map元素delete()
delete(map, key)
訪問map元素
value,ok = map[key],如果key存在,則返回值value和nil,如果不存在,返回零值和false
新增與更新
map[key] = value 若key不存在則新增,存在則更新
通道channel
1.go 關鍵字用來建立 goroutine (協程),是實現併發的關鍵
2.channel 用來進行多個goroutine通訊的,可以設定快取大小,在未被填滿前不會發生阻塞(預設為0,
無緩衝)
3.無緩衝的通道是一批資料一進一出, 有緩衝的通道則是一個一個儲存,然後一起流出去
4.select 可以處理一個或多個 channel 的傳送與接收
使用 make(chan val-type) 建立一個新的通道
ch := make(chan int)
//go 關鍵字建立一個協程
go loop(ch)
go loop(ch)
func loop(ch chan int) {
for i := 0; i < 8; i++ {
fmt.Println(i)
}
ch <- 1 //傳送值到通道
}
關閉通道close
close(ch)
函式、結構體、方法、介面
函式
func main() {
fmt.Println(Add(8, 7))
fmt.Println(Subtraction(8, 7))
}
func Add(number1 int, number2 int) (number3 int) {
number3 = number1 + number2
return
}
func Subtraction(number1, number2 int) int {
number3 := number1 - number2
return number3
}
匿名函式
//匿名函式1
//f1 為函式地址
f1 := func(x, y int) (z int) {
z = x + y
return
}
fmt.Println(f1)
fmt.Println(f1(5, 6))
//匿名函式2
//直接建立匿名函式並執行
f2 := func(x, y int) (z int) {
z = x + y
return
}(7, 8)
fmt.Println(f2)
//匿名函式3(無引數的形式)
func() {
fmt.Println(9 + 10)
}() //不明白為什麼後面要加個括號
閉包函式
func main() {
//函式內在包含子函式,並最終return子函式
n1 := number1(7)
fmt.Println(n1(8))
n2 := number2()
n2()
}
結構體struct
把各種資料型別定義的不同變數組合起來
type Person struct {
Name string
Age int
}
方法
type Calculation struct {
number1 int
number2 int
}
func (c Calculation) Add() int {
number3 := c.number1 + c.number2
return number3
}
介面interface
1.go中只要某個型別擁有該介面的所有方法簽名,即算實現該介面,不需要顯示指定
2.任何型別都實現了空介面 interface{}
type geometry interface {
area() int64
perimeter() int64
}
指標
操作符"&“取變數地址,使用”*"通過指標間接訪問目標物件
number1 := 10
var number2 *int = &number1
fmt.Println(number2)
fmt.Println(*number2)
傳值與傳指標
- 當我們傳一個引數值到被呼叫函式裡面時,實際上是傳了這個值的一份copy,當在被呼叫函式中修改引數值的時候,呼叫函式中相應實參不會發生任何變化,因為數值變化只作用在copy上
- 變數在記憶體中是存放於一定地址上的,修改變數實際是修改變數地址處的記憶體
- 傳指標使得多個函式能操作同一個物件
- 傳指標比較輕量級 (8bytes),只是傳記憶體地址,我們可以用指標傳遞體積大的