Golang 速查表

來源:互聯網
上載者:User

譯文地址:blog
原文:golang-cheat-sheet

簡要概括 Go 文法及特性。

目錄

  1. 基礎文法
  2. 運算子

    • 算術運算子
    • 比較子
    • 邏輯運算子
    • 其他
  3. 聲明
  4. 函數

    • 函數作為值和回調使用
    • 可變參數函數
  5. 內建類型
  6. 類型轉換
  7. package
  8. 流程式控制制結構

    • 條件判斷(if)
    • 迴圈(for)
    • 多條件分支(switch)
  9. array, slice, range

    • array
    • slice
    • array 和 slice 的操作函數
  10. map
  11. 結構體
  12. 指標
  13. 介面
  14. 結構體和介面的組合嵌入
  15. Errors
  16. 並發

    • goroutine
    • channel
    • channel 開發原則
  17. 輸出
  18. 程式碼片段

    • Http-Server

前言

參考

文中大部分代碼都摘抄自 A Tour of Go,對新手來說是很好的參考資料。

Go 特性

  • 命令式編程
  • 靜態類型
  • 類 C 文法(括弧使用頻率更少 & 無需分號),類 Oberon-2 的文法結構
  • 代碼能編譯為本地可執行檔(無需 JVM 類的虛擬機器)
  • structmethod 取代類的概念
  • 介面
  • 類型組合 取代顯式繼承
  • 有頭等函數
  • 有回呼函數
  • 函數可有多個傳回值
  • 保留指標,但不能直接參与算術運算
  • 內建並發原語:goroutinechannel

基礎文法

Hello World

檔案 hello.go

package mainimport "fmt"func main() {    fmt.Println("Hello Go")}

運行:$ go run hello.go

運算子

算術運算子

運算子 描述
+
-
*
/
% 取餘
& 按位與
¦ 按位或
^ 按位異或
&^ 按位清除(AND NOT)
<< 左移
>> 右移

&^ 即是 AND NOT(x, y) = AND(x, NOT(Y)),如:

package mainimport "fmt"func main() {    x := 0xDC    // 11011100    y := 0xF0    // 11110000    z := x &^ y    // 00001100    // y 中為 1 的位全部被清除為 0    fmt.Printf("%08b", z)}

比較子

運算子 描述
== 相等
!= 不等
< 小於
<= 小於等於
> 大於
>= 大於等於

邏輯運算子

運算子 描述
&& 邏輯與
¦¦ 邏輯或
! 取反

其他

運算子 描述
& 定址(產生指標)
* 擷取指標指向的資料
<- 向 channel 中發送 / 接收資料

聲明

與 C 不同,類型放在標識符後面:

var foo int             // 無初值的聲明var foo int = 42         // 帶初值的聲明var foo, bar int = 42, 1302    // 一次性聲明並初始化多個變數var foo = 42             // 類型推斷,由使用的上下文決定foo := 42             // 簡短聲明,只能用在函數內部const constant = "This is a constant"

函數

// 最簡單的函數func functionName() {}// 帶參數的函數(注意類型也是放在標識符之後的)func functionName(param1 string, param2 int) {}// 類型相同的多個參數func functionName(param1, param2 int) {}// 聲明傳回值的類型func functionName() int {    return 42}// 一次返回多個值func returnMulti() (int, string) {    return 42, "foobar"}var x, str = returnMulti()// 只使用 return 返回多個命名傳回值func returnMulti2() (n int, s string) {    n = 42    s = "foobar"    // n 和 s 會被返回    return}var x, str = returnMulti2()

函數作為值和回調使用

func main() {    // 將函數作為值,賦給變數    add := func(a, b int) int {        return a + b    }    // 使用變數直接調用函數    fmt.Println(add(3, 4))}// 回呼函數範圍:在定義回呼函數時能訪問外部函數的值func scope() func() int{    outer_var := 2    foo := func() int { return outer_var}    return foo}func another_scope() func() int{    // 編譯錯誤,兩個變數不在此函數範圍內    // undefined: outer_var    outer_var = 444    return foo}// 回呼函數不會修改外部範圍的資料func outer() (func() int, int) {    outer_var := 2    inner := func() int {        outer_var += 99     // 試著使用外部範圍的 outer_var 變數        return outer_var     // 傳回值是 101,但只在 inner() 內部有效    }    return inner, outer_var    // 傳回值是 inner, 2 (outer_var 仍是 2)}inner, outer_var := outer();    // inner, 2inner();    // 返回 101inner();    // 返回 200    // 回呼函數的特性

可變參數函數

func main() {    fmt.Println(adder(1, 2, 3))     // 6    fmt.Println(adder(9, 9))    // 18        nums := []int{10, 20, 30}    fmt.Println(adder(nums...))    // 60}// 在函數的最後一個參數類型前,使用 ... 可表明函數還能接收 0 到多個此種類型的參數// 下邊的函數在調用時傳多少個參數都可以func adder(args ...int) int {    total := 0    for _, v := range args {    // 使用迭代器逐個訪問參數        total += v    }    return total}

內建類型

boolstringint  int8  int16  int32  int64uint uint8 uint16 uint32 uint64 uintptrbyte // uint8 類型的別名    // 儲存 raw datarune // int32 類型的別名    // 一個 Unicode code point 字元float32 float64complex64 complex128

類型轉換

var i int = 42var f float64 = float64(i)var u uint = uint(f)// 簡化文法i := 42f := float64(i)u := uint(f)

package

  1. package 在源檔案開頭聲明
  2. main package 才是可執行檔
  3. 約定:package 名字與 import 路徑的最後一個單詞一致(如匯入 math/rand 則 package 叫 rand)
  4. 大寫開頭的標識符(變數名、函數名…):對其他 package 是可訪問的
  5. 小寫開頭的標識符:對其他 package 是不可見的

流程式控制制結構

if

func main() {    // 一般的條件判斷    if x > 0 {        return x    } else {        return -x    }            // 在條件判斷語句前可塞一條語句,使代碼更簡潔    if a := b + c; a < 42 {        return a    } else {        return a - 42    }        // 使用 if 做類型斷言    var val interface{}    val = "foo"    if str, ok := val.(string); ok {        fmt.Println(str)    }}

Loops

// Go 語言中迴圈結構只有 for,沒有 do、while、until、foreach 等等for i := 1; i < 10; i++ {}for ; i < 10;  {     // 等效於 while 迴圈}for i < 10  {         // 只有一個判斷條件時可省去分號}for {             // 無條件迴圈時,等效於 while(true)}

switch

// switch 分支語句switch operatingSystem {    case "darwin":        fmt.Println("Mac OS Hipster")        // case 語句內建 break,想執行所有 case 需要手動 fallthrough    case "linux":        fmt.Println("Linux Geek")    default:        // Windows, BSD, ...        fmt.Println("Other")}// 和 if、for 語句一樣,可在判斷變數之前加入一條指派陳述式switch os := runtime.GOOS; os {    case "darwin": ...}// 在 switch 中還能做比較,相當於 switch (true) {...}number := 42switch {    case number < 42:        fmt.Println("Smaller")    case number == 42:        fmt.Println("Equal")    case number > 42:        fmt.Println("Greater")}// 多個 case 可使用逗號分隔統一處理var char byte = '?'switch char {    case ' ', '?', '&', '=', '#', '+', '%':    fmt.Println("Should escape")} 

Arrays, Slices, Ranges

Arrays

var a [10]int // 聲明長度為 10 的 int 型數組,注意數群組類型 = (元素類型 int,元素個數 10)a[3] = 42     // 設定元素值i := a[3]     // 讀取元素值// 聲明並初始化數組var a = [2]int{1, 2}a := [2]int{1, 2}     // 簡短聲明a := [...]int{1, 2}    // 數組長度使用 ... 代替,編譯器會自動計算元素個數

slices

var a []int                   // 聲明 slice,相當於聲明未指定長度的數組var a = []int {1, 2, 3, 4}    // 聲明並初始化 slice (基於 {} 中給出的底層數組)a := []int{1, 2, 3, 4}        // 簡短聲明chars := []string{0:"a", 2:"c", 1: "b"}  // ["a", "b", "c"]var b = a[lo:hi]    // 建立從 lo 到 hi-1 的 slice var b = a[1:4]        // 建立從 1  到 3    的 slicevar b = a[:3]        // 預設 start index 則預設為 0 var b = a[3:]        // 預設 end   index 則預設為 len(a)a =  append(a,17,3)    // 向 slice a 中追加 17 和 3c := append(a,b...)    // 合并兩個 slice// 使用 make 建立 slicea = make([]byte, 5, 5)    // 第一個參數是長度,第二個參數是容量a = make([]byte, 5)    // 容量參數是可選的// 從數組建立 slicex := [3]string{"Лайка", "Белка", "Стрелка"}s := x[:]         // slice s 指向底層數組 x

數組和 slice 的操作函數

// 迭代數組或 slicefor i, e := range a {    // i 是索引    // e 是元素值}// 如果你只要值,可用 _ 來丟棄返回的索引for _, e := range a {}// 如果你只要索引for i := range a {}// 在 Go 1.4 以前的版本,如果 i 和 e 你都不用,直接 range 編譯器會報錯for range time.Tick(time.Second) {    // 每隔 1s 執行一次}

map

var m map[string]intm = make(map[string]int)m["key"] = 42fmt.Println(m["key"])delete(m, "key")elem, ok := m["key"] // 檢查 m 中是否鍵為 key 的元素,如果有 ok 才為 true// 使用索引值對的形式來初始化 mapvar m = map[string]Vertex{    "Bell Labs": {40.68433, -74.39967},    "Google":    {37.42202, -122.08408},}

結構體

Go 語言中沒有 class 類的概念,取而代之的是 struct,struct 的方法對應到類的成員函數。

// struct 是一種類型,也是欄位成員的集合體// 聲明 structtype Vertex struct {    X, Y int}// 初始化 structvar v = Vertex{1, 2}            // 欄位名有序對應值var v = Vertex{X: 1, Y: 2}         // 欄位名對應值var v = []Vertex{{1,2},{5,2},{5,5}}    // 初始化多個 struct 組成的 slice// 訪問成員v.X = 4// 在 func 關鍵字和函數名之間,聲明接收者是 struct// 在方法內部,struct 執行個體被複製,傳值引用func (v Vertex) Abs() float64 {    return math.Sqrt(v.X*v.X + v.Y*v.Y)}// 調用方法(有接收者的函數)v.Abs()// 有的方法接收者是指向 struct 的指標// 此時在方法內調用執行個體,將是傳址引用func (v *Vertex) add(n float64) {    v.X += n    v.Y += n}

匿名結構體

使用 map[string]interface{} 開銷更小且更為安全。

point := struct {    X, Y int}{1, 2}

指標

p := Vertex{1, 2}  // p 是一個 Vertexq := &p            // q 是指向 Vertex 的指標r := &Vertex{1, 2} // r 也是指向 Vertex 的指標var s *Vertex = new(Vertex) // new 返回的指向該執行個體指標

介面

// 聲明介面type Awesomizer interface {    Awesomize() string}// 無需手動聲明 implement 介面type Foo struct {}// 自訂類型如果實現了介面的所有方法,那它就自動實現了該介面func (foo Foo) Awesomize() string {    return "Awesome!"}

結構體和介面的組合嵌入

// 實現 ReadWriter 的類型要同時實現了 Reader 和 Writer 兩個介面type ReadWriter interface {    Reader    Writer}// Server 暴露出 Logger 所有開放的方法type Server struct {    Host string    Port int    *log.Logger}// 初始化自訂的組合類別型server := &Server{"localhost", 80, log.New(...)}// 組合的結構體能直接跨節點調用方法server.Log(...) // 等同於調用 server.Logger.Log(...)// 欄位同理var logger *log.Logger = server.Logger

Errors

Go 中沒有異常處理機制,函數在調用時在有可能會產生錯誤,可返回一個 Error 類型的值,Error 介面:

type error interface {    Error() string}

一個可能產生錯誤的函數:

func doStuff() (int, error) {}func main() {    result, err := doStuff()    if err != nil {        // 錯誤處理    }    // 使用 result 處理正常邏輯}

並發

goroutine

goroutine(協程)是輕量級的線程(Go runtime 自行管理,而不是作業系統),代碼 go f(a, b) 就開了一個運行 f 函數的協程。

func doStuff(s string) {}func main() {    // 在協程中執行函數    go doStuff("foobar")    // 在協程中執行匿名函數    go func (x int) {        // 函數實現    }(42)}

Channels

ch := make(chan int)     // 建立類型為 int 的 channelch <- 42                 // 向 channel ch 寫資料 42v := <-ch                // 從 channel ch 讀資料,此時 v 的值為 42            // 無緩衝的 channel 此時會阻塞            // 如果 channel 中無資料,則讀操作會被阻塞,直到有資料可讀// 建立帶緩衝的 channel// 向帶緩衝的 channel 寫資料不會被阻塞,除非該緩衝區已滿ch := make(chan int, 100)close(ch) // 寄件者主動關閉 channel// 在從 channel 讀資料的同時檢測其是否已關閉// 如果 ok 為 false,則 ch 已被關閉v, ok := <-ch    // 從 channel 中讀資料直到它被關閉for i := range ch {    fmt.Println(i)}// select 語句中 任一 channel 不阻塞則自動執行對應的 casefunc doStuff(channelOut, channelIn chan int) {    select {        case channelOut <- 42:            fmt.Println("We could write to channelOut!")        case x := <- channelIn:            fmt.Println("We could read from channelIn")        case <-time.After(time.Second * 1):            fmt.Println("timeout")    }}

channel 開發原則

1.向 nil channel 寫資料將卡死,一直阻塞

2.從 nil channel 讀資料將卡死,一直阻塞

3.向已關閉的 channel 寫資料將造成 panic

package mainfunc main() {    var c = make(chan string, 1)    c <- "Hello, World!"    close(c)    c <- "Hello, Panic!"}

運行:

4.從已關閉的 channel 讀資料將返回零值

package mainfunc main() {    var c = make(chan int, 2)    c <- 1    c <- 2    close(c)    for i := 0; i < 3; i++ {        println(<-c)    }}

運行:

輸出

fmt.Println("Hello, 你好, नमस्ते, Привет, ᎣᏏᏲ")         // 最基本的輸出,會自動加一個換行p := struct { X, Y int }{ 17, 2 }fmt.Println( "My point:", p, "x coord=", p.X )         // 輸出結構體欄位等s := fmt.Sprintln( "My point:", p, "x coord=", p.X )    // 組合字元串並返回fmt.Printf("%d hex:%x bin:%b fp:%f sci:%e",17,17,17,17.0,17.0) // 類 C 的格式化輸出s2 := fmt.Sprintf( "%d %f", 17, 17.0 )            // 格式化字串並返回hellomsg := ` "Hello" in Chinese is 你好 ('Ni Hao') "Hello" in Hindi is नमस्ते ('Namaste')` // 聲明多行字串,在前後均使用反引號 `

程式碼片段

HTTP Server

package mainimport (    "fmt"    "net/http")// 定義響應的資料結構type Hello struct{}// Hello 實現 http.Handler 中定義的 ServeHTTP 方法func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {    fmt.Fprint(w, "Hello!")}func main() {    var h Hello    http.ListenAndServe("localhost:4000", h)}// http.ServeHTTP 在介面內的定義如下:// type Handler interface {//     ServeHTTP(w http.ResponseWriter, r *http.Request)// }

運行:

總結

上邊十七個知識點簡要概括了常見文法,可複習使用,但涉及到的細節不多,細讀《Go 程式設計語言》 才是。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.