1. 程式人生 > >Go語法筆記

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),只是傳記憶體地址,我們可以用指標傳遞體積大的