Skip to content

Go 語言速查表

Go(又稱 Golang)是 Google 的 Robert Griesemer, Rob Pike 及 Ken Thompson 開發的一種靜態強類型、編譯型語言。Go 語言語法與 C 相近,但功能上有:記憶體安全,GC(垃圾回收),結構形態及 CSP-style 併發計算。

Hello world

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) (string) {
  return "Hello, " + name + "!"
}
$ go build

變數

變數宣告

var msg string
msg = "Hello"

簡寫

msg := "Hello"

常數

const Phi = 1.618

常數可以是字元、字串、布林值或數值。

基礎類型

字串

str := "Hello"
str := `Multiline
string`

字串的類型是 string

數值

典型類型

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (uint8 的別名)

其他類型

var u uint = 7        // uint (無符號)
var p float32 = 22.7  // 32-bit float

指標

func main () {
  b := *getPointer()
  fmt.Println("Value is", b)
}
 
func getPointer () (myPointer *int) {
  a := 234
  return &a
}

指標指向變數的記憶體位置。Go 具有完全垃圾回收功能。

陣列

// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}

陣列的大小是固定的。

切片

slice := []int{2, 3, 4}
slice := []byte("Hello")

與陣列不同,切片具有動態大小。

流程控制

條件判斷

if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}

if 中的語句

if _, err := getResult(); err != nil {
  fmt.Println("Uh oh")
}

if 語句可以在條件表達式前執行一個簡單的語句。

Switch

switch day {
  case "sunday":
    // 預設情況下,case 不會「穿透」(fall through)!
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}

函數

Lambdas (匿名函數)

myfunc := func() bool {
  return x > 10000
}

函數是一等公民 (first-class objects)。

多個回傳類型

a, b := getMessage()
func getMessage() (a string, b string) {
  return "Hello", "World"
}

具名回傳值

func split(sum int) (x, y int) {
  x := sum * 4 / 9
  y := sum - x
  return
}

透過在宣告中命名回傳值,return(無參數)將回傳具有這些名稱的變數。

封裝包 (Packages)

載入

import "fmt"
import "math/rand"
import (
  "fmt"        // 提供 fmt.Println
  "math/rand"  // 提供 rand.Intn
)

兩者是相同的。

別名

import r "math/rand"
 
r.Intn()

導出的名稱

func Hello () {
  ···
}

導出的名稱以大寫字母開頭。

封裝包宣告

package hello

每個封裝包檔案都必須以 package 開頭。

併發

Goroutines

func main() {
  // 「通道」(channel)
  ch := make(chan string)

  // 啟動併發常式
  go push("Moe", ch)
  go push("Larry", ch)
  go push("Curly", ch)

  // 讀取 3 個結果
  // (由於我們的 goroutines 是併發的,
  // 順序無法保證!)
  fmt.Println(<-ch, <-ch, <-ch)
}
 
func push(name string, ch chan string) {
  msg := "Hey, " + name
  ch <- msg
}

通道是併發安全的通訊物件,在 goroutines 中使用。

緩衝通道

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// fatal error:
// all goroutines are asleep - deadlock!

緩衝通道限制了它可以保存的消息數量。

關閉通道

關閉通道

ch <- 1
ch <- 2
ch <- 3
close(ch)

遍歷一個通道直到它關閉

for i := range ch {
  ···
}

如果 ok == false 則表示已關閉

v, ok := <- ch

錯誤控制与延遲執行

Defer

func main() {
  defer fmt.Println("Done")
  fmt.Println("Working...")
}

將函數的執行延遲到周圍函數回傳為止。參數會立即求值,但函數呼叫直到最後才會執行。

使用 Lambda 的 Defer

func main() {
  defer func() {
    fmt.Println("Done")
  }()
  fmt.Println("Working...")
}

Lambdas 更適合延遲執行區塊。

結構體 (Structs)

定義

type Vertex struct {
  X int
  Y int
}

func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X, v.Y)
}

字面量

v := Vertex{X: 1, Y: 2}
// 欄位名稱可以省略
v := Vertex{1, 2}
// Y 是隱含的
v := Vertex{X: 1}

您也可以指定欄位名稱。

指向結構體的指標

v := &Vertex{1, 2}
v.X = 2

v 是指標時,執行 v.X(*v).X 是一樣的。

方法

接收器 (Receivers)

type Vertex struct {
  X, Y float64
}
func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
 
v := Vertex{1, 2}
v.Abs()

Go 沒有類別 (Class),但您可以使用接收器為類型定義函數。

指標接收器

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}
 
v := Vertex{6, 12}
v.Scale(0.5)
// `v` 會被更新