Go學習筆記

來源:互聯網
上載者:User
簡介 Go語言 Go是一種開放源碼的程式設計語言,它意在使得人們能夠方便地構建簡單、可靠、高效的軟體。 Go有時被稱為“類C語言”或“21世紀的C”。從C中,Go整合了運算式文法、控制流程語句、基礎資料型別 (Elementary Data Type)、按值調用的形參傳遞、指標,但比這些更重要的是,繼承了C所強調的程式要編譯成高效的機器碼,並自然地與所處的作業系統提供的抽象機制相配合。 程式結構 一個Go程式儲存在一個或多個以尾碼為 .go 的檔案當中。每個檔案在最開頭包含包(package)聲明,來指定該檔案屬於哪個包。包聲明後面的是匯入(import)聲明,用來匯入程式中用到的庫。匯入聲明後面是包層級(package-level)的聲明,包括類型、變數、常量以及函數的聲明,包層級的聲明在相同檔案和相同包中的其他檔案都可見。在函數中聲明的變數為局部變數,只在函數中可見。 main函數是程式的入口。

例子:

package main  // 包聲明import "fmt"  // 匯入聲明const pi = 3.14  // 包層級的聲明func main() {  // main 同樣是包層級的聲明    var f = 123.456  // 局部聲明    fmt.Printf("f = %g\n", f)}
變數和常量 標識符 Go語言中的命名和其他語言無異:字母、數字、底線的組合,但第一個字元不能是數字。 Go語言中的名字區分大小寫。 不能用關鍵字作為名字。 命名長度沒有限制,但在Go的傳統裡越短越好。可見度越廣,定義越長的名字就越不容易起衝突。 Go習慣用駝峰式命名。例如:parseRequestLine 如果名稱中包含首字母縮減詞,則在命名時不用駝峰式命名。例如:HTMLEscape,escapeHTML而不是escapeHtml 關鍵字

Go有25個關鍵字:

break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
變數 變數聲明 用var聲明定義變數以及它的類型和初值:var name type = expression
類型或者= expression部分可以省略,但不能兩者同時省略。 如果類型省略,則編譯器根據expression推斷類型。 如果省略= expression,則該變數初始為0值:
- 數字初始為0
- 布爾值初始為false
- 字串初始為空白
- 介面和引用初始為nil
- 數組和結構體將其中的元素或欄位初始為0值

一次聲明多個變數:

var i, j, k int   // int, int, intvar b, f, s = true, 2.3, "four"  // bool float64 string

多個變數聲明為函數的傳回值:

var f, err = os.Open(name)  // os.Open returns a file and an error

如果聲明了一個變數,卻沒有使用它,則會報錯。 簡短的變數聲明 在函數裡可以使用簡短的變數聲明:name := expression,name的類型根據expression推斷。 初始化多個變數:i, j := 0, 1

多個變數聲明為函數傳回值:

f, err := os.Open(name)

多變數聲明時不必所有變數都是新建立的變數,但必須至少有一個是新建立的變數。多變數聲明中已經建立過的變數視為賦值:

// 假設in,err和out都沒有被聲明過in, err := os.Open(infile)  // ok, 聲明in和err//...out, err := os.Create(outfile)  // ok, 聲明out,給err賦值
// 假設f,err沒有被聲明過f, err := os.Open(infile)//...f, err := os.Create(outfile)  // 編譯錯誤,沒有新變數被建立
變數賦值 賦值運算子:= 任何算數運算子或者位元運算符後面接=則組成複合賦值運算子,例如:+=,*=

數值變數可以使用自增和自減運算子是自身的值加1或減1。沒有前置自增。

v := 1v++  // same as v = v + 1; v becomes 2v--  // same as v = v - 1; v becomes 1 again
多重賦值

多重賦值允許一次賦值多個變數:

i, j, k = 2, 3, 5x, y = y, x  // 交換兩個變數的值

若函數或操作符返回多個值,則在賦值左側必須用多個變數,個數必須與傳回值的個數一致:

f, err = os.Open("foo.txt")  // function call return two values

如果不想用多個函數傳回值中的某個或某幾個,則可以用_代替:

_, err = io.Copy(dst, src)
隱式賦值 隱式賦值發生在函數參數傳遞,函數傳回值等情況。 指標 指標儲存一個變數的地址。指標用*後面加類型的方式表示,例如:*int

用&取一個變數的地址。用*訪問指標所指的變數,例如:

x := 0p := &x*p = 1  // x now is 1
指標的0值為nil

可以返回函數內的局部變數的地址

var p = f()func f() *int {    v := 1    return &v  // ok}
new函數

new函數建立一個匿名對象並返回它的地址,這個對象的初始值設為0值:

p := new(int)  // p is *int, *p is 0

返回局部變數的地址,與返回new建立的變數等效:

func newInt() *int {    return new(int)}// 等效於:func newInt() *int {    var dummy int    return &dummy}
空標識

空標識 _,用於在文法上需要一個變數,但是邏輯上不需要變數的時候。比如 range for 中不需要的變數, 函數傳回值列表中不需要的傳回值。

a := [3]string{"hello","go","world"}for _, v := range a {  // 不需要索引值,以_代替    fmt.Print(v, " ")}_, x := func() (int, int) {  // 不需要第一個傳回值,以_代替    return 1, 2}()
變數的可見度 如果一個變數定義在函數裡,那麼它是局部的。 如果一個變數定義在所有函數外,則它在包裡的所有檔案中都可見。並且,如果名稱首字母是大寫,則在包外亦可見。(包的名字總是小寫) 變數的生命期 包變數(全域變數)的生命期與程式的生命期一致。局部變數的生命期從生命開始到該變數不可見為止。 Go語言有記憶體回收機制,因此不必擔心記憶體的開闢和釋放問題。 變數是在堆上還是在棧上建立取決於該變數的生命期。
若函數返回局部變數的地址,則該變數被分配在堆上。 若變數僅在局部(函數體內,迴圈體內,if語句內等等)使用,則該變數分配在棧上,即使是用new()函數建立的變數也是如此。 函數是被建立在棧上還是堆上由編譯器決定,無需程式員幹預。 詞塊 範圍表示一個名字的作用範圍。 詞塊(lexical block)表示一個作用範圍,該範圍內限定了名字的範圍。以下範圍都稱為詞塊:整個原始碼(又稱為全域塊(universe block))、包、檔案、函數、for語句內、if語句內、switch語句內、case語句內,每一對大括弧內。 在不同詞塊內可聲明同一個名字,內部詞塊中的名字會隱藏外部詞塊中的名字,但這是一種不好的風格。 常量 常量的聲明 用const聲明常量:const pi = 3.14159

聲明多個常量用括弧括起:

const (    e = 2.718281    pi = 3.14159)

常量可用作數組的維度:

const len = 4var p [len]byte

const聲明一組常量時除第一常量以外可以分配預設值,該值與上一個常量一致:

const (    a = 1    b      // b is 1    c = 2    d      // d is 2)
常量產生器iota

在聲明一組常量時,可以使用iota 組成的運算式給第一個常量賦值,第一個常量之後的每一個常量都應用這個運算式,但iota的值從0開始,每到下一個常量便加一,通常以這種方式賦值的常量又叫枚舉。

const (    a = iota  // a is 0    b         // b is 1    c         // c is 2    d         // d is 3)const (    flag1 = 1 << iota  // flag1 is 1 (1 << 0)    flag2              // flag2 is 2 (1 << 1)    flag3              // flag3 is 4 (1 << 2)    flag4              // flag4 is 8 (1 << 3))
無類型常量

沒有冠以類型的常量為無類型常量,無類型常量在被賦予類型之前要比有類型常量有更大的精度(通常精度可高達256位),並且能參與精度更大的計算:

const (    a = 1 << (100 + iota)    b     // b為100位的整數,已經超過了最大的uint64的值    c     // c為101位的整數     )fmt.Printf("%d", c/b)  // print 2

無類型常量根據常量的字面形式,分為無類型整數,無類型浮點數,無類型bool值,無類型rune,無類型複數:

const (    a = 100       // 無類型整數    b = 1.0       // 無類型浮點數    c = true      // 無類型bool值    d = '\u1234'  // 無類型rune    e = 3 + 2i    // 無類型複數)
基礎資料型別 (Elementary Data Type) 整數 整數類型
類型 符號 位元 範圍 說明
int8


有符號
8


−2n−1−1∼2n−1−1 -2^{n-1}-1 \sim 2^{n-1}-1
int16 16
int32 32
rune 32 rune是int32的別名,
用來表示Unicode碼點(code point)。
int64 64
uint8


無符號
8


0∼2n−1 0 \sim 2^n-1
uint16 16
uint32 32
uint64 64
int 有符號

不同的編譯器根據不同的平台設定不同的大小,
以達到最高效的利用硬體。
uint 無符號
uintptr 無符號 uintptr是一個無符號整型,
僅用來相容低級語言(比如C)。
整型除了可以用10進位表示外,還可以用8進位和16進位表示。8進位前加0,16進位前加0x或者0X。 操作符

可用於整型的操作符和優先順序如下(優先順序從高到低,每行優先順序相同):

* / % << >> & &^
+ + − - | ^
== != < <= > >=
&&
||

前兩行的操作符都有一個對應的複合賦值操作符,比如+對應+= 算術運算子+ - * /可用於整型、浮點型、複數。 模數運算子(%)僅可用於兩個整型。如果模數時有負數,則最後的符號由被除數決定,比如:-5%3 與 -5%-3 結果都為 -2 算術運算子的結果可能超出運算元的類型的範圍。這就引發了溢出。運算時應注意選用合適的類型做運算,以免溢出。 比較子 == != < <= > >=可應用於兩個類型相同的基基本類型(整型、浮點型、字串),結果為bool類型。 + - 亦可作為一元運算子,表示正負。

Go提供了如下的位元運算符:

& 按位與
| 按位或
^ 異或
&^ 與非
<< 左位移
>> 右位移
^亦可作為一元運算子,表示按位取反。 &^表示與非,例如:z = x &^ y,如果y的某一位為1,則z的該位為0,否則z的該位和x的該位一致。 << 與 >>的右運算元必須為無符號數。>>的左運算元若為有符號數,則向右移的時候用符號位填補空位。 列印整型

在使用fmt.Printf()列印整型時,10進位、8進位、16進位分別用 %d %o %x(或%X表示大寫) :

o := 0123fmt.Printf("%d %[1]o %#[1]o\n", o)  // 83 123 0123x := int64(0xABC)fmt.Printf("%d %[1]x %#[1]x %#[1]X\n", x)  // 2748 abc 0xabc 0XABC
# 表示列印8進位或16進位開頭的字元 []內的數字表示要從列印序列中取出第幾個運算元

列印rune類型用 %c(不帶引號)或者 %q(帶引號),列印出的是Unicode字元:

ch := '中'ch2 := '國'fmt.Printf("%d %[1]c %d %[2]q\n", ch, ch2)  // 20013 中 22269 '國'
浮點數 浮點數類型
類型 精度 最大值 最小值
float32 6位 math.MaxFloat32 math.MinFloat32
float64 15位 math.MaxFloat64 math.MinFloat64
列印浮點數 用%f列印浮點數 特殊值:
特殊值 意義 例子
+Inf 正無窮 5.0/0.0
-Inf 負無窮 -5.0/0.0
NaN Not a Number 0/0
math.IsNaN 測試一個值是否為NaN math.NaN 返回NaN NaN與NaN比較為false 複數 Go語言內建複數類型。有兩種複數類型:complex64 complex128,complex64的實部和虛部位float32,complex128的實部和虛部是float64。 用complex()建立一個複數類型,real()和imag()返回實部和虛部。虛部的字面值以數字後面加i表示。 Go支援複數的四則運算。比較操作符支援:== 和 != 布爾值 Go語言的bool值僅有true和false。 以下操作產生bool值: 比較操作符:> >= < <= == !=),邏輯非:! 兩個產生bool值的運算式可以用邏輯與(&&)和邏輯或(||)連在一起,併產生短路行為(貌似所有的語言都是如此,至少我所知的是如此)。 不能將數值或指標類型隱式轉換成布爾值,反之亦然。 字串 字串是一串byte序列。用string表示。 字串通常以UTF8編碼儲存Unicode碼點(rune)。 len()函數返回字串中byte的個數, 非Unicode字元的個數。假設s是字串,則下標操作符s[i]返回字串中第i個byte的值, 非第i個Unicode字元。 Go支援字串切片:s[i:j]返回從第i個byte開始到第j個byte結束(不包含第j個byte)的字串。切片時可以省略i和j當中的任意一個或全部。省略i則從0開始,省略j則到len(s)結束,都省略則表示從0到len(s)的字串(即本身)。 string支援+操作符以拼接字串。支援+=以拼接新的字串並賦值給變數自身。 string支援比較操作符。以byte為單位逐一比較。 字串是不能改變的。例如 s[0]='v'得到編譯錯誤。正是因為字串不能改變,切片所返回的字串可以和原字串共用同一段記憶體,以提高效率。 字串字面值 雙引號(”)或反引號( `)括起的byte序列為字串字面值。
雙引號字串中轉義以\開始的字元 反引號字串中不轉義以\開始的字元 逸出字元可以用16進位(以\x開頭,後面接兩個16進位字元,比如\xAB)或者8進位(以\開頭,比如\377)表示。

常用的逸出字元:

字元 意義
\n 換行
\r 斷行符號
\t 定位字元
\’ 單引號
\” 雙引號
\\ 反斜線
反引號括起的字串叫做原始字串(raw string),其中以\開始的字元不轉義。原始字串可以跨越多行,但是Go會自動去掉其中的斷行符號(\r),以使原始字串在Linux和Windows下保持一致。原始字串可以用在Regex中以避免過多的轉義。 因為Go程式源碼總是儲存為UTF8,而字串也通常也以UTF8解析。所以可以在字串字面值中寫任何Unicode碼點。 UTF-8 UTF-8以變長的方式編碼Unicode。 Go的原始碼以UTF-8方式儲存。源碼中的字串也是以UTF-8方式處理。 Unicode轉義:16位:\uhhhh;32位:\Uhhhhhhhh

只有小於256的單個16進位數可以轉義為一個rune,否則只能通過/u或/U的方式來轉換:

var a rune = '\x41'  // oka = '\xe4\xb8\x96'  // errora = '\u4e16'  // ok

unicode/utf8包裡提供了UTF-8和rune相關的函數:

DecodeRuneInString接受一個字串,並返回該字串的第一個字元的rune值以及表示這個rune需要的byte數量:

s := "你好"r, size := utf8.DecodeRuneInString(s)fmt.Printf("%q is %d bytes", r, size)  // 列印: '你' is 3 bytes

RuneCountInString返回字串中rune的個數

s := "你好"fmt.Printf("rune count: %d\nbyte count: %d",     utf8.RuneCountInString(s), len(s))// 列印:// rune count: 2// byte count: 6

range for 自動解碼UTF-8字串為tune序列:

s := "你好"for i, r := range s {    fmt.Printf("%d: %q\n", i, r)}// 列印:// 0: '你'// 3: '好'
Go的解碼器在解碼UTF-8時,如果遇到非法字元序列,則轉換為\uFFFD,這個字元一般是一個多邊形的黑塊中間有個。的字元:� rune與UTF-8字串互轉:
string轉為[]rune會自動解碼,得到相應的rune序列。 []rune轉為string會自動編碼,得到相應的UTF-8字串。 數字轉string會將數字先轉為rune,然後對該rune進行編碼產生相應的字串。 複合類型 數組 數組是一個或多個 同類型元素組成的 固定長度的序列。表示為[num]T,其中num是元素個數,T是類型,例如:[3]int 表示元素個數為3的int數組。

數組的聲明:

var a [3]int  // 建立一個由3個int值組成的數組

數組初始化

用數組字面值初始化:

var a [3]int = [3]int{1, 2, 3}

未被顯式初始化的元素被隱式初始化為0值:

var a [3]int = [3]int{1, 2}  // a[2] is 0var b [3]int  // 所有元素都為0

若以 ... 指定數組長度,則由初始化列表中元素的個數決定數組真實長度:

q := [...]int{1, 2, 3} // q is [3]int

初始化時可以指定下標:

a = [...]string{1:"he
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.