25個關鍵字
程序聲明:import, package
程序實體聲明和定義:chan, const, func, interface, map, struct, type, var
程序流程控制:go, select, break, case, continue, default, defer, else, fallthrough, for, goto, if, range, return
類型
18個基本類型:bool, string, rune, byte, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float32, float64, complex64, complex128
7個復合類型:array, struct, function, interface, slice, map, channel
其中,切片、字典、通道類型都是引用類型
類型的聲明一般以 type 關鍵字開始,然后是自定義的標識符名稱,然后是基本類型的名稱或復合類型的定義。
Unicode字符rune類型是和int32等價的類型,通常用於表示一個Unicode碼點。這兩個名稱可以互換使用。同樣byte也是uint8類型的等價類型,byte類型一般用於強調數值是一個原始的數據而不是一個小的整數。
最后,還有一種無符號的整數類型uintptr,沒有指定具體的bit大小但是足以容納指針。uintptr類型只有在底層編程是才需要,特別是Go語言和C語言函數庫或操作系統接口相交互的地方。
一個float32類型的浮點數可以提供大約6個十進制數的精度,而float64則可以提供約15個十進制數的精度;通常應該優先使用float64類型,因為float32類型的累計計算誤差很容易擴散,並且float32能精確表示的正整數並不是很大
操作符
列舉一些特殊的操作符,注意下面的位操作符
& 位運算 AND | 位運算 OR ^ 位運算 XOR &^ 位清空 (AND NOT) << 左移 >> 右移
可以通過 Printf 函數的 %b 參數來輸出二進制格式的數字。
特殊的空標識符
下划線 _ 作為一個特殊的標識符,可以用於 import 語句中,僅執行導入包中的 init 方法。也可以作為賦值語句的左邊,表示該變量並不關心且不使用。
此外,標識符首字母的大小寫,在GO語言中被用來控制變量或函數的訪問權限,類似於其它語言的 public\private。
類型斷言
比較特殊的表達式有類型斷言,如果判斷一個表達式 element 的類型是 T 的話,表達式為 element.(T),意思是 element 不為 nil 且存儲在其中的值是T類型。這里有兩種情況,如果 T 不是一個接口類型,則 element 必須要為接口類型的值,比如判斷 100 是 int 型,不能使用 100.(int),而要用 interface{}(100).(int) ; 如果T 是一個接口類型,表示斷言 element 實現了 T 這個接口。如果函數的參數是一個空接口,則必須斷言傳入的接口實現類型,才能使用其對應的方法。
可變參函數
最后一個參數為 ...T 的形式的函數即為可變參函數,意味着可變參數都是 T 類型(或實現了T的類型)如:func CallFunction(first string, t ...string),GO語言會在調用可變參函數時,創建一個切片,然后將這些可變參數放入切片中,但如果傳入的可變參部分就是一個元素類型為T的切片的話,則直接把傳入切片賦值給創建的切片,且在調用寫法上也有區別,為: CallFunction("hello", []string{"x","y"}...)
數組類型
array: 聲明一個長度為 n 、元素類型為 T 的數組為: [n]T, 元素類型可以為基本類型也可以為復合類型,也可以不指定 n ,由推導得出,如: [...]string{"a","b"} , 數組長度 n = len([...]string{"a","b"}),另外如果指定了數組長度,但定義的數組長度小於聲明的長度,則以聲明長度為准,不足的元素補默認值。同一元素類型,但數組長度不同,則視為不同類型。
切片類型
slice: 切片類型的聲明為 []T數組,切片類型里沒有關於長度的規定,其它跟數組一樣,切片類型的零值是 nil。切片總是對應於一個數組,其對應的數組稱為底級數組。切片和其底層數組的關系是引用關系,如果有修改都會影響到對方。
切片的數據結構包含了指向其底層數組的指針、切片長度和切片容量。切片的長度很容易理解,切片的容量是什么呢,它是切片第一個元素到底層數組最后一個元素的長度。
字典類型
map: 定義一個哈希表的格式為 map[K]V,其中 K 表示鍵的類型,V表示值的類型,如: map[string]bool{"IsOK":true, "IsError":false}
接口類型
定義了一組方法聲明,接口中可以包含接口
GO語言對接口類型的實現是非侵入式的(備注:侵入式是指用戶代碼與框架代碼有依賴,而非侵入式則沒有依賴,或者說耦合),只要一個類型定義了某個接口中聲明的所有方法,就認為它實現了該接口。
一個特殊的接口: interface{} 是一個空接口,不包含任何方法聲明,所以GO語言所有的類型都可以看成是它的實現類型,我們就可以使用它實現類似其它語言中的公共基類的功能。比如聲明一個字典,鍵是字符串,值是不確定類型,就可以使用 map[string]interface{}
判斷一個類型是否實現了一個接口,可以通過類型斷言來確定: _, ok := interface{}(MyType{}).(MyInterface)
函數與方法
GO語言中,函數跟方法是有區別的,函數就是我們通常理解的函數,而方法是附屬於某個自定義數據類型的函數,即存在某個接收者。
func (self MyType) Len() int {} 這里的 (self MyInterface) 是表示方法接收者。
值方法和指針方法,值方法是指接收者是一個對象,而指針方法是指接收者是一個對象指針。兩者的區別是,值方法中對接收者的改變是副本級別的,而指針方法中對接收者的改變是地址級別的。所以其實一般都推薦使用指針方法,因為大多數情況下我們在方法內部修改接收者,都是為了真實的改變它,而不是改變一個副本。但是,對於引用類型的接收者來說,兩者並無區別。
匿名函數由函數字面量表示,函數是作為值存在的,可以賦給函數類型的變量。如:
var myfunc func(int, int) int myfunc = func(x, y int) (result int) { result = x + y return } log.Println(myfunc(3, 4))
一個方法的類型是一個函數類型,即把接收者放到函數的第一個參數位置即可。
非常遺憾,GO語言不支持函數和方法重載。
結構體
可以包含字段,也可以包含匿名字段,一般匿名字段是接口類型,這樣就相當於該結構體包含了該接口中的方法,另外也可以在結構里重寫隱藏接口中的方法。
指針
有一個專門用於存儲內存地址的類型 unitptr,它與 int/unit 一樣屬於數值類型,存儲32/64位無符號整數。
可以在一個類型前面使用*號,來表示對應的指針類型,也可以在可尋址的變量前面使用&,來獲取其地址。
常量
定義常量和多個常量如下:
const PP = iota //0 const QQ = iota //0 const ( A = 1 B = 2 C D = iota E F ) log.Print(A, B, C, D, E, F) //輸出是: 1 2 2 3 4 5
注意,iota 只能在 const 里使用,它是 const 的行數索引器,其值是所在const組中的索引值,單常量定義時 iota 就等於 0。另外,const組中某一項如果不賦值,則默認和上一個值一樣,但如果前面是 iota ,則為上一個值+1。使用 iota 可以實現其它語言中的枚舉。
變量
變量的聲明語句以 var 開始,聲明多個變量時,和聲明多個const的方法相同。
var x string = "df" var x = "df" x := "df" //此為簡寫形式。
數據初始化
GO語言的數據初始化有兩種方法,一是使用 new ,一是使用 make ,其中 new 是為某個類型分配內存,並設置零值后返回地址,如 new(T) 返回的就是指向T類型值指針值,即*T。如 new([3]int) 其實相當於 [3]int{0,0,0},所以它是一種很干凈的內存分配策略。
make 只用於創建切片類型、字典類型和通道類型(注意這三個類型的特點,都是引用類型),它對這些類型創建之后,還會進行必要的初始化,與 new 不同,它返回的就是指T類型的值,而不是指針值。
定義常量的方式是使用 const ,如 const PI = 3.14,如果定義多個常量可以使用
編譯器會自動選擇在棧上還是在堆上分配局部變量的存儲空間,但可能令人驚訝的是,這個選擇並不是由用var還是new聲明變量的方式決定的。 如果一個函數里聲明一個局部變量,但是將其指針賦給一個全局變量,那么則不能將此局部變量放在棧中,而只能放在堆中,我們可以稱之為該局部變量逃逸了,所以關於變量是分配在棧上還是堆上,是由編譯器根據情況來選擇的。
內建函數
close 只接受通道類型的值
len函數,可以應用於字符串、切片、數組、字典、通道類型
cap函數,可以應用於切片、數組、通道類型
new函數和make函數
append函數和copy函數,應用於切片
delete函數,根據字典的鍵刪除某一項
complex\real\imag函數,復數相關
panic 函數,異常相關,它的參數一般是某個error接口的某個實現類型;recover 函數,不接受任何參數,返回 interface{} 類型,也就是意味着,它可以返回任意類型。recover返回的內容是與panic相關的,就是panic的參數內容。
print\println 函數,這兩個函數支持基本類型參數,且是可變參數。但輸出格式是固定的,且GO語言不保證以后會保留這兩個函數,所以知道就好,不推薦使用。可以使用 fmt.Print 和 fmt.Println 來代替,效果更佳。
合並書寫:
和 var/const 類似,多個 type 定義可合並成組,如下:
type ( Person struct { Name string Age int32 } myfunc func(string) bool )
尤其是在函數內部定義一堆臨時類型時,可集中書寫,可讀性更好。
自增/自減運算符不同於其它語言,不能用作表達式,只能當獨立的語句使用,且不能前置,只有后置形式,以盡可能避免該運算符帶的復雜性問題。
unsafe.Pointer 與 uintptr 的區別:
前者類似 C 語言中的 void* 萬能指針,能安全持有對象,但后者不行,后者只是一種特殊整型,並不引用目標對象,無法阻止垃圾回收器回收對象內存。