1. 程式人生 > >Go語言規範-型別

Go語言規範-型別

文章目錄

型別

型別決定了值與可在值上應用的操作及方法。型別可以用型別名來標記,也可以用組合型別的型別字面來標記。
組合型別有:陣列、結構、指標、函式、介面、切片、對映、通道,都可以用型別字面來構造。
每個型別都有基礎型別,對於預定義的型別(布林型、數值型)、字串型別、型別字面,基礎型別就是它自己。其他情況下,型別T的基礎型別就是T在其型別宣告中引用的型別的基礎型別

方法集

型別可以有相關聯的方法集。介面型別的方法集就是它的介面。對於其他型別T,聲明瞭接收者為型別T的所有方法就是它的方法集。而相應的指標型別T的方法集則是聲明瞭接收者為T和T所有方法(也就是包含了型別T的方法集)。對於結構型別,有些特定的規則留在結構型別中說。其他的型別具有空方法集。在方法集中,每個方法都要有一個唯一的非空的方法名。

布林型別

用預定義的常量true和false來標記布林真值。預定義的布林型別是bool,它是一個被定義的型別(defined type.)。

數值型別

預定義的架構無關的數值型別有:

uint8       所有無符號8位整數 (0 to 255)
uint16      所有無符號16位整數(0 to 65535)
uint32      所有無符號32位整數(0 to 4294967295)
uint64      所有無符號64位整數 (0 to 18446744073709551615)

int8        所有有符號8位整數 (-128 to 127)
int16       所有有符號16位整數 (-32768 to 32767)
int32       所有有符號32位整數 (-2147483648 to 2147483647)
int64       所有有符號64位整數 (-9223372036854775808 to 9223372036854775807)

float32     所有IEEE-754 32位浮點數
float64     所有IEEE-754 64位浮點數

complex64   所有具有float32 實數和虛數部分的複數
complex128  所有具有float64 實數和虛數部分的複數

byte        uint8的別名
rune        int32的別名

還有一些預定義的大小與平臺相關的數值型別:

uint     either 32 or 64 bits
int      same size as uint
uintptr  an unsigned integer large enough to store the uninterpreted bits of a pointer value

為了避免移植性問題,所有的數值型別都是被定義的型別,除了byte和rune,它們是別名。在不同的數值型別混合在一個表示式或語句中時,需要轉換型別。

字串型別

字串型別是一系列(可能是0個)位元組,它一旦建立就不可修改。預定義的型別是string,它是一個被定義的型別。
使用內建的函式len可以獲取字串的長度(位元組數),如果字串是個常量,其長度就是一個編譯期常數。可以用下標0~len(s)-1來訪問字串中的指定位元組,但不能取其地址,&s[i]是非法的。

陣列型別

陣列是單一型別(稱為元素型別)的指定了數量的一系列元素,元素的數量稱為長度且永不為負值。長度是陣列型別的一部分,必須被求值為一個值型別為int的的常量表達。可以使用內建的len函式來得到陣列長度。其元素可以用下標0~len(a)-1來定址。陣列都是一維的,但可以組合成多維型別。

[32]byte
[2*N] struct { x, y int32 }
[1000]*float64
[3][5]int
[2][2][2]float64  // same as [2]([2]([2]float64))

切片型別

切片是基礎陣列的一個連續片段的描述符,提供了對該陣列中指定數量的一系列元素的訪問。
與陣列相同的是切片也可以被索引、也有長度、長度也可以用內建函式len來獲得。與陣列不同的是它在執行中可以改變。其元素可以用下標0~len(a)-1來定址,但某元素的下標可能比基礎陣列中相應元素的下標小。
切片一經初始化就與持有其元素的基礎陣列關聯起來。因此它與基礎陣列以及基礎陣列上的其他切片一起共享儲存。
切片的下層陣列可以擴充套件超過切片的尾部。所以使用容量來度量這個擴充套件:它是切片的長度加上陣列超過切片的那部分長度。可以用內建函式cap來獲得切片的容量。
與陣列一樣,切片總是一維的,但可以通過組合來構造高維度的物件。對於陣列的陣列,其內層陣列總是具有相同的長度,但對於切片的切片,或是切片的陣列,其內層的長度可以是不同的。值得一提的是,內層的切片必須單獨初始化。

結構型別

結構就是一系列命名的元素(稱為欄位),每個欄位有一個名字和型別。欄位的名字可以顯式指定也可以隱式指定。非空欄位名都必須是唯一的。

// An empty struct.
struct {}

// A struct with 6 fields.
struct {
	x, y int
	u float32
	_ float32  // padding
	A *[]int
	F func()
}

對於一個聲明瞭欄位型別但沒有顯式名字的欄位,稱為嵌入欄位。嵌入欄位必須指定為型別名T或一個非介面型別名的指標*T,T本身不能是指標型別。未修飾的型別名會作為欄位名:

// A struct with four embedded fields of types T1, *T2, P.T3 and *P.T4
struct {
	T1        // field name is T1
	*T2       // field name is T2
	P.T3      // field name is T3
	*P.T4     // field name is T4
	x, y int  // field names are x and y
	// *T1    // 與欄位名T1衝突
	//*P.T1   // 未修飾的型別名是T1,與欄位名T1衝突
}

對於結構x的嵌入欄位的欄位或方法f,如果x.f是標記該欄位或方法f的合法的選擇器,那麼稱f是被提升的。
被提升的欄位的行為就像是結構原本的欄位,但是在結構字面中不能用做欄位名。
給定一個結構型別S和一個被定義的型別T,結構的方法集中根據以下規則來決定是否包含被提升的方法:

  • 如果S包含了嵌入欄位T,則S和*S的方法集都包含了接收者為T的被提升方法;*S的方法集還包括了接受者為*T的方法集
  • 如果S包含了嵌入欄位*T,則S和*S的方法集都包含了接收者為T和*T的被提升方法

欄位宣告還可以跟著一個字串字面的標籤,它為成為相應欄位宣告的一個屬性。空的標籤相當於沒有標籤。通過反射介面標籤才會可見並參與結構的型別標識,否則會被忽略。

struct {
	x, y float64 ""  // 空標籤串相當於沒有
	name string  "任何字串都可以當標籤"
	_    [4]byte "這不是結構的欄位"
}

// 一個對應TimeStamp協議緩衝區的結構.
// 標籤定義了協議緩衝區欄位號;
// 它們遵循reflect包中的約定
struct {
	microsec  uint64 `protobuf:"1"`
	serverIP6 uint64 `protobuf:"2"`
}

指標型別

指標型別標記了指向給定型別(稱為指標的基型別)的變數的指標。沒有初始化的指標的值為nil。

*Point
*[4]int

函式型別

函式型別標記了所有具有相同引數和返回值型別的函式。
引數列表或結果中,名字要麼都要有,要麼都沒有。如果有,一個名字表示一個所指型別的元素(引數或結果),所有的非空名字必須唯一。如果沒有,每個型別表示一個所指型別的元素。引數和結果列表總要使用圓括號包圍,如果只有一個沒名字的結果,則該結果可以省略為不帶圓括號的型別名。
最後一個入參可以是一個字首…的型別。這樣的函式稱為可變參函式,此引數可代表0或多個引數。

//無返回值無引數
func()
// 一個名字為x的int型引數,有一個int型返回值
func(x int) int
// 一個名字為a的int型引數,一個空的int型引數,一個名字為z的float32型引數,返回值為bool型
func(a, _ int, z float32) bool
func(a, b int, z float32) (bool)
// 有int型可變引數
func(prefix string, values ...int)
// 有任意型別可變引數,返回一個名為success的bool型值
func(a, b int, z float64, opt ...interface{}) (success bool)
// 返回值有兩個,分別是float64型和[]int型指標
func(int, int, float64) (float64, *[]int)
//返回值是個函式型別
func(n int) func(p *T)

介面型別

介面型別指定了一組方法為它的介面。一個型別T的方法集如果是一個介面型別I的介面的超集,則可以儲存到型別為I的變數中。而T稱為實現了介面I。
一個型別可以在它的方法的子集中實現任意的介面,從而實現多個不同的介面。例如,所有的型別都實現了空介面:

interface {}

介面中的所有方法都必須具有唯一且非空的名字。
介面可以用另一個介面型別的名字來替代方法宣告,這稱為介面嵌入。此情況下,被嵌入的介面的所有方法都被納入外層介面。介面的嵌入不可遞迴。

對映型別

通過某一型別(稱鍵型別)關鍵字索引一組無序的另一型別(稱元素型別)元素,就是對映。
鍵型別必須要定義比較操作符==和!=,因此,鍵型別不能是函式、對映或切片。如果鍵型別是介面型別,必須為動態鍵值定義這些比較操作符.失敗會導致執行時異常。
對映中元素的數量稱為長度,可用內建的len函式來獲取。長度在執行期可變。可以使用賦值語句來增加元素有索引表示式來獲取元素,使用內建delete函式來刪除元素。
沒有初始化的對映值為nill,不能為它增加元素。

通道型別

通過一個特定元素型別的值的傳遞,通道提供了併發執行函式之間通訊的機制。

chan int
chan <- float64
<- chan byte

其中的 <-操作符指定了通道的方向——傳送還是接收。如果沒有指定方向,通道就是雙向的。通道可以通過型別轉化或是賦值來限制其方向。
<-操作符是左結合操作符:

chan <- chan int     // chan<- (chan int)
chan <- <- chan int  // chan<- (<-chan int)
<-chan <-chan int    // <-chan (<-chan int)

通道可以帶有快取,如果通道沒快取,則只在收發雙方都就緒的情況下通訊才能成功。如果通道有快取,則在快取未滿(傳送時)或不空(接收時)的情況下通訊會立即成功而不是阻塞。
通道可以用內建函式close來關閉。接收操作符可以使用多值賦值的形式來判斷所接收的值是不是在在通道關閉之前傳送的。
單個通道在多個goroutines同進傳送、接收以及使用內建函式cap、len時都不需要額外的同步操作。通道是先進先出佇列。