類型(type)可以被看作是值(value)的模板,值可以被看作是類型的實(shí)例。 這篇文章將介紹內(nèi)置(或稱為預(yù)聲明的)基本類型和它們字面量的表示形式。 本篇文章不介紹組合類型。
Go支持如下內(nèi)置基本類型:
bool
。int8
、uint8
、int16
、uint16
、int32
、uint32
、int64
、uint64
、int
、uint
和uintptr
。float32
和float64
。complex64
和complex128
。string
。內(nèi)置類型也稱為預(yù)聲明類型。
這17種內(nèi)置基本類型(type)各自屬于一種Go中的類型種類(kind)。 盡管所有的內(nèi)置基本類型的名稱都是非導(dǎo)出標(biāo)識(shí)符, 我們可以不用引入任何代碼包而直接使用這些類型。
除了bool
和string
類型,其它的15種內(nèi)置基本類型都稱為數(shù)值類型(整型、浮點(diǎn)數(shù)型和復(fù)數(shù)型)。
Go中有兩種內(nèi)置類型別名(type alias):
byte
是uint8
的內(nèi)置別名。 我們可以將byte
和uint8
看作是同一個(gè)類型。rune
是int32
的內(nèi)置別名。 我們可以將rune
和int32
看作是同一個(gè)類型。以u
開(kāi)頭的整數(shù)類型稱為無(wú)符號(hào)整數(shù)類型。 無(wú)符號(hào)整數(shù)類型的值都是非負(fù)的。 一個(gè)數(shù)值類型名稱中的數(shù)字表示每個(gè)這個(gè)類型的值將在內(nèi)存中占有多少二進(jìn)制位(以后簡(jiǎn)稱位)。二進(jìn)制位常稱為比特(bit)。 比如,一個(gè)uint8
的值將占有8位。 我們稱uint8
類型的值的尺寸是8位。 因此,最大的uint8
值是255
(28-1), 最大的int8
值是127
(27-1),
最小的int8
值是-128
(-27)。
任一個(gè)類型的所有值的尺寸都是相同的,所以一個(gè)值的尺寸也常稱為它的類型的尺寸。
更多的時(shí)候,我們使用字節(jié)(byte)做為值尺寸的度量單位。 一個(gè)字節(jié)相當(dāng)于8個(gè)比特。所以uint32
類型的尺寸為4,即每個(gè)uint32
值占用4個(gè)字節(jié)。
uintptr
、int
以及uint
類型的值的尺寸依賴于具體編譯器實(shí)現(xiàn)。 通常地,在64位的架構(gòu)上,int
和uint
類型的值是64位的;在32位的架構(gòu)上,它們是32位的。 編譯器必須保證uintptr
類型的值的尺寸能夠存下任意一個(gè)內(nèi)存地址。
一個(gè)complex64
復(fù)數(shù)值的實(shí)部和虛部都是float32
類型的值。 一個(gè)complex128
復(fù)數(shù)值的實(shí)部和虛部都是float64
類型的值。
在內(nèi)存中,所有的浮點(diǎn)數(shù)都使用IEEE-754格式存儲(chǔ)。
一個(gè)布爾值表示一個(gè)真假。在內(nèi)存中,一個(gè)布爾值只有兩種可能的狀態(tài)。 這兩種狀態(tài)使用兩個(gè)預(yù)聲明(或稱為內(nèi)置)的常量(false
和true
)來(lái)表示。 關(guān)于常量聲明,下一篇文章將做詳細(xì)解釋。
從邏輯上說(shuō),一個(gè)字符串值表示一段文本。 在內(nèi)存中,一個(gè)字符串存儲(chǔ)為一個(gè)字節(jié)(byte)序列。 此字節(jié)序列體現(xiàn)了此字符串所表示的文本的UTF-8編碼形式。 我們可以從Go中的字符串一文中獲取更多關(guān)于字符串的知識(shí)。
盡管布爾和字符串類型分類各自只有一種內(nèi)置類型, 我們可以聲明定義更多自定義布爾和字符串類型。 所以,Go代碼中可以出現(xiàn)很多布爾和字符串類型(數(shù)值類型也同樣)。 下面是一個(gè)類型聲明的例子。 在這些例子中,type
是一個(gè)關(guān)鍵字。
// 一些類型定義聲明
type status bool // status和bool是兩個(gè)不同的類型
type MyString string // MyString和string是兩個(gè)不同的類型
type Id uint64 // Id和uint64是兩個(gè)不同的類型
type real float32 // real和float32是兩個(gè)不同的類型
// 一些類型別名聲明
type boolean = bool // boolean和bool表示同一個(gè)類型
type Text = string // Text和string表示同一個(gè)類型
type U8 = uint8 // U8、uint8和 byte表示同一個(gè)類型
type char = rune // char、rune和int32表示同一個(gè)類型
我們將上面定義的real
類型和內(nèi)置類型float32
都稱為float32類型 (注意這里的第二個(gè)float32是一個(gè)泛指,而第一個(gè)高亮的float32是一個(gè)特指)。 同樣地,MyString
和string
都被稱為字符串(string)類型,status
和bool
都被稱為布爾(bool)類型。
我們將在Go類型系統(tǒng)概述一文中學(xué)習(xí)到更多關(guān)于自定義類型的知識(shí)。
每種類型都有一個(gè)零值。一個(gè)類型的零值可以看作是此類型的默認(rèn)值。
一個(gè)值的字面形式稱為一個(gè)字面量,它表示此值在代碼中文字體現(xiàn)形式(和內(nèi)存中的表現(xiàn)形式相對(duì)應(yīng))。一個(gè)值可能會(huì)有很多種字面量形式。
Go白皮書沒(méi)有定義布爾類型值字面量形式。 我們可以將false
和true
這兩個(gè)預(yù)聲明的具名常量當(dāng)作布爾類型的字面量形式。 但是,我們應(yīng)該知道,從嚴(yán)格意義上說(shuō),它們不屬于字面量。具名常量聲明將在下一篇文章中介紹和詳細(xì)解釋。
布爾類型的零值可以使用預(yù)聲明的false
來(lái)表示。
整數(shù)類型值有四種字面量形式:十進(jìn)制形式(decimal)、八進(jìn)制形式(octal)、十六進(jìn)制形式(hex)和二進(jìn)制形式(binary)。 比如,下面的三個(gè)字面量均表示十進(jìn)制的15:
0xF // 十六進(jìn)制表示(必須使用0x或者0X開(kāi)頭)
0XF
017 // 八進(jìn)制表示(必須使用0、0o或者0O開(kāi)頭)
0o17
0O17
0b1111 // 二進(jìn)制表示(必須使用0b或者0B開(kāi)頭)
0B1111
15 // 十進(jìn)制表示(必須不能用0開(kāi)頭)
(注意:二進(jìn)制形式和以0o
或0O
開(kāi)頭的八進(jìn)制形式從Go 1.13開(kāi)始才支持。)
下面的程序打印出兩個(gè)true
。
package main
func main() {
println(15 == 017) // true
println(15 == 0xF) // true
}
注意這里的==
是一個(gè)等于比較操作符。 操作符將在后續(xù)的文章常用操作符一文中詳細(xì)解釋。
整數(shù)類型的零值的字面量一般使用0
表示。 當(dāng)然,00
和0x0
等也是合法的整數(shù)類型零值的字面量形式。
一個(gè)浮點(diǎn)數(shù)的完整十進(jìn)制字面量形式可能包含一個(gè)十進(jìn)制整數(shù)部分、一個(gè)小數(shù)點(diǎn)、一個(gè)十進(jìn)制小數(shù)部分和一個(gè)以10為底數(shù)的整數(shù)指數(shù)部分。 整數(shù)指數(shù)部分由字母e
或者E
帶一個(gè)十進(jìn)制的整數(shù)字面量組成(xEn
表示x
乘以10n
的意思,而xE-n
表示x
除以10n
的意思)。
常常地,某些部分可以根據(jù)情況省略掉。一些例子:
1.23
01.23 // == 1.23
.23
1.
// 一個(gè)e或者E隨后的數(shù)值是指數(shù)值(底數(shù)為10)。
// 指數(shù)值必須為一個(gè)可以帶符號(hào)的十進(jìn)制整數(shù)字面量。
1.23e2 // == 123.0
123E2 // == 12300.0
123.E+2 // == 12300.0
1e-1 // == 0.1
.1e0 // == 0.1
0010e-2 // == 0.1
0e+5 // == 0.0
從Go 1.13開(kāi)始,Go也支持另一種浮點(diǎn)數(shù)字面量形式:十六進(jìn)制浮點(diǎn)數(shù)字面量。 在一個(gè)十六進(jìn)制浮點(diǎn)數(shù)字面量中,
p
或者P
帶一個(gè)十進(jìn)制的整數(shù)字面量組成(yPn
表示y
乘以2n
的意思,而yP-n
表示y
除以2n
的意思)。0x
或者0X
開(kāi)頭。 和整數(shù)的十六進(jìn)制字面量不同的是,一個(gè)十六進(jìn)制浮點(diǎn)數(shù)字面量可以包括一個(gè)小數(shù)點(diǎn)和一個(gè)十六進(jìn)制小數(shù)部分。一些合法的浮點(diǎn)數(shù)的十六進(jìn)制字面量例子:
0x1p-2 // == 1.0/4 = 0.25
0x2.p10 // == 2.0 * 1024 == 2048.0
0x1.Fp+0 // == 1+15.0/16 == 1.9375
0X.8p1 // == 8.0/16 * 2 == 1.0
0X1FFFP-16 // == 0.1249847412109375
而下面這幾個(gè)均是不合法的浮點(diǎn)數(shù)的十六進(jìn)制字面量。
0x.p1 // 整數(shù)部分表示必須包含至少一個(gè)數(shù)字
1p-2 // p指數(shù)形式只能出現(xiàn)在浮點(diǎn)數(shù)的十六進(jìn)制字面量中
0x1.5e-2 // e和E不能出現(xiàn)在十六進(jìn)制浮點(diǎn)數(shù)字面量的指數(shù)部分中
注意:下面這個(gè)表示是合法的,但是它不是浮點(diǎn)數(shù)的十六進(jìn)制字面量。事實(shí)上,它是一個(gè)減法算術(shù)表達(dá)式。其中的e
為是十進(jìn)制中的14
,0x15e
為一個(gè)整數(shù)十六進(jìn)制字面量,-2
并不是此整數(shù)十六進(jìn)制字面量的一部分。 (算術(shù)運(yùn)算將在后續(xù)的文章常用操作符一文中詳細(xì)介紹。)
0x15e-2 // == 0x15e - 2 (整數(shù)相減表達(dá)式)
浮點(diǎn)類型的零值的標(biāo)準(zhǔn)字面量形式為0.0
。 當(dāng)然其它很多形式也是合法的,比如0.
、.0
、0e0
和0x0p0
等。
一個(gè)虛部值的字面量形式由一個(gè)浮點(diǎn)數(shù)字面量或者一個(gè)整數(shù)字面量和其后跟隨的一個(gè)小寫的字母i
組成。 在Go 1.13之前,如果虛部中i
前的部分為一個(gè)整數(shù)字面量,則其必須為并且總是被視為十進(jìn)制形式。 一些例子:
1.23i
1.i
.23i
123i
0123i // == 123i(兼容性使然。見(jiàn)下)
1.23E2i // == 123i
1e-1i
011i // == 11i(兼容性使然。見(jiàn)下)
00011i // == 11i(兼容性使然。見(jiàn)下)
// 下面這幾行從Go 1.13開(kāi)始才能編譯通過(guò)。
0o11i // == 9i
0x11i // == 17i
0b11i // == 3i
0X.8p-0i // == 0.5i
注意:在Go 1.13之前,虛部字面量中字母i
前的部分只能為浮點(diǎn)數(shù)字面量。 為了兼容老的Go版本,從Go 1.13開(kāi)始,一些虛部字面量中表現(xiàn)為(不以0o
和0O
開(kāi)頭的)八進(jìn)制形式的整數(shù)字面量仍被視為浮點(diǎn)數(shù)字面量。 比如上例中的011i
、0123i
和00011i
。
虛部字面量用來(lái)表示復(fù)數(shù)的虛部。下面是一些復(fù)數(shù)值的字面量形式:
1 + 2i // == 1.0 + 2.0i
1. - .1i // == 1.0 + -0.1i
1.23i - 7.89 // == -7.89 + 1.23i
1.23i // == 0.0 + 1.23i
復(fù)數(shù)零值的標(biāo)準(zhǔn)字面表示為0.0+0.0i
。 當(dāng)然0i
、.0i
、0+0i
等表示也是合法的。
從Go 1.13開(kāi)始,下劃線_
可以出現(xiàn)在整數(shù)、浮點(diǎn)數(shù)和虛部數(shù)字面量中,以用做分段符以增強(qiáng)可讀性。 但是要注意,在一個(gè)數(shù)值字面表示中,一個(gè)下劃線_
不能出現(xiàn)在此字面表示的首尾,并且其兩側(cè)的字符必須為(相應(yīng)進(jìn)制的)數(shù)字字符或者進(jìn)制表示頭。
一些合法和不合法使用下劃線的例子:
// 合法的使用下劃線的例子
6_9 // == 69
0_33_77_22 // == 0337722
0x_Bad_Face // == 0xBadFace
0X_1F_FFP-16 // == 0X1FFFP-16
0b1011_0111 + 0xA_B.Fp2i
// 非法的使用下劃線的例子
_69 // 下劃線不能出現(xiàn)在首尾
69_ // 下劃線不能出現(xiàn)在首尾
6__9 // 下劃線不能相連
0_xBadFace // x不是一個(gè)合法的八進(jìn)制數(shù)字
1_.5 // .不是一個(gè)合法的十進(jìn)制數(shù)字
1._5 // .不是一個(gè)合法的十進(jìn)制數(shù)字
上面已經(jīng)提到,rune
類型是int32
類型的別名。 因此,rune類型(泛指)是特殊的整數(shù)類型。 一個(gè)rune值可以用上面已經(jīng)介紹的整數(shù)類型的字面量形式表示。 另一方面,很多各種整數(shù)類型的值也可以用本小節(jié)介紹的rune字面量形式來(lái)表示。
在Go中,一個(gè)rune值表示一個(gè)Unicode碼點(diǎn)。 一般說(shuō)來(lái),我們可以將一個(gè)Unicode碼點(diǎn)看作是一個(gè)Unicode字符。 但是,我們也應(yīng)該知道,有些Unicode字符由多個(gè)Unicode碼點(diǎn)組成。 每個(gè)英文或中文Unicode字符值含有一個(gè)Unicode碼點(diǎn)。
一個(gè)rune字面量由若干包在一對(duì)單引號(hào)中的字符組成。 包在單引號(hào)中的字符序列表示一個(gè)Unicode碼點(diǎn)值。 rune字面量形式有幾個(gè)變種,其中最常用的一種變種是將一個(gè)rune值對(duì)應(yīng)的Unicode字符直接包在一對(duì)單引號(hào)中。比如:
'a' // 一個(gè)英文字符
'π'
'眾' // 一個(gè)中文字符
下面這些rune字面量形式的變種和'a'
是等價(jià)的 (字符a
的Unicode值是97)。
'\141' // 141是97的八進(jìn)制表示
'\x61' // 61是97的十六進(jìn)制表示
'\u0061'
'\U00000061'
注意:\
之后必須跟隨三個(gè)八進(jìn)制數(shù)字字符(0-7)表示一個(gè)byte值, \x
之后必須跟隨兩個(gè)十六進(jìn)制數(shù)字字符(0-9,a-f和A-F)表示一個(gè)byte值, \u
之后必須跟隨四個(gè)十六進(jìn)制數(shù)字字符表示一個(gè)rune值(此rune值的高四位都為0), \U
之后必須跟隨八個(gè)十六進(jìn)制數(shù)字字符表示一個(gè)rune值。 這些八進(jìn)制和十六進(jìn)制的數(shù)字字符序列表示的整數(shù)必須是一個(gè)合法的Unicode碼點(diǎn)值,否則編譯將失敗。
下面這些println
函數(shù)調(diào)用都將打印出true
。
package main
func main() {
println('a' == 97)
println('a' == '\141')
println('a' == '\x61')
println('a' == '\u0061')
println('a' == '\U00000061')
println(0x61 == '\x61')
println('\u4f17' == '眾')
}
事實(shí)上,在日常編程中,這四種rune字面量形式的變種很少用來(lái)表示rune值。 它們多用做字符串的雙引號(hào)字面量形式中的轉(zhuǎn)義字符(詳見(jiàn)下一小節(jié))。
如果一個(gè)rune字面量中被單引號(hào)包起來(lái)的部分含有兩個(gè)字符, 并且第一個(gè)字符是\
,第二個(gè)字符不是x
、 u
和U
,那么這兩個(gè)字符將被轉(zhuǎn)義為一個(gè)特殊字符。 目前支持的轉(zhuǎn)義組合為:
\a (rune值:0x07) 鈴聲字符
\b (rune值:0x08) 退格字符(backspace)
\f (rune值:0x0C) 換頁(yè)符(form feed)
\n (rune值:0x0A) 換行符(line feed or newline)
\r (rune值:0x0D) 回車符(carriage return)
\t (rune值:0x09) 水平制表符(horizontal tab)
\v (rune值:0x0b) 豎直制表符(vertical tab)
\\ (rune值:0x5c) 一個(gè)反斜杠(backslash)
\' (rune值:0x27) 一個(gè)單引號(hào)(single quote)
其中,\n
在日常編程中用得最多。
一個(gè)例子:
println('\n') // 10
println('\r') // 13
println('\'') // 39
println('\n' == 10) // true
println('\n' == '\x0A') // true
rune類型的零值常用 '\000'
、'\x00'
或'\u0000'
等來(lái)表示。
在Go中,字符串值是UTF-8編碼的, 甚至所有的Go源代碼都必須是UTF-8編碼的。
Go字符串的字面量形式有兩種。 一種是解釋型字面表示(interpreted string literal,雙引號(hào)風(fēng)格)。 另一種是直白字面表示(raw string literal,反引號(hào)風(fēng)格)。 下面的兩個(gè)字符串表示形式是等價(jià)的:
// 解釋形式
"Hello\nworld!\n\"你好世界\""
// 直白形式
`Hello
world!
"你好世界"`
在上面的解釋形式(雙引號(hào)風(fēng)格)的字符串字面量中,每個(gè)\n
將被轉(zhuǎn)義為一個(gè)換行符,每個(gè)\"
將被轉(zhuǎn)義為一個(gè)雙引號(hào)字符。 雙引號(hào)風(fēng)格的字符串字面量中支持的轉(zhuǎn)義字符和rune字面量基本一致,除了一個(gè)例外:雙引號(hào)風(fēng)格的字符串字面量中支持\"
轉(zhuǎn)義,但不支持\'
轉(zhuǎn)義;而rune字面量則剛好相反。
以\
、\x
、\u
和\U
開(kāi)頭的rune字面量(不包括兩個(gè)單引號(hào))也可以出現(xiàn)在雙引號(hào)風(fēng)格的字符串字面量中。比如:
// 這幾個(gè)字符串字面量是等價(jià)的。
"\141\142\143"
"\x61\x62\x63"
"\x61b\x63"
"abc"
// 這幾個(gè)字符串字面量是等價(jià)的。
"\u4f17\xe4\xba\xba"
// “眾”的Unicode值為4f17,它的UTF-8
// 編碼為三個(gè)字節(jié):0xe4 0xbc 0x97。
"\xe4\xbc\x97\u4eba"
// “人”的Unicode值為4eba,它的UTF-8
// 編碼為三個(gè)字節(jié):0xe4 0xba 0xba。
"\xe4\xbc\x97\xe4\xba\xba"
"眾人"
在UTF-8編碼中,一個(gè)Unicode碼點(diǎn)(rune)可能由1到4個(gè)字節(jié)組成。 每個(gè)英文字母的UTF-8編碼只需要一個(gè)字節(jié);每個(gè)中文字符的UTF-8編碼需要三個(gè)字節(jié)。
直白反引號(hào)風(fēng)格的字面表示中是不支持轉(zhuǎn)義字符的。 除了首尾兩個(gè)反引號(hào),直白反引號(hào)風(fēng)格的字面表示中不能包含反引號(hào)。 為了跨平臺(tái)兼容性,直白反引號(hào)風(fēng)格的字面表示中的回車符(Unicode碼點(diǎn)為0x0D
) 將被忽略掉。
字符串類型的零值在代碼里用 ""
或``
表示。
一個(gè)數(shù)值型的字面量只有在不需要舍入時(shí),才能用來(lái)表示一個(gè)整數(shù)基本類型的值。 比如,1.0
可以表示任何基本整數(shù)類型的值,但1.01
卻不可以。 當(dāng)一個(gè)數(shù)值型的字面量用來(lái)表示一個(gè)非整數(shù)基本類型的值時(shí),舍入(或者精度丟失)是允許的。
每種數(shù)值類型有一個(gè)能夠表示的數(shù)值范圍。 如果一個(gè)字面量超出了一個(gè)類型能夠表示的數(shù)值范圍(溢出),則在編譯時(shí)刻,此字面量不能用來(lái)表示此類型的值。
下表是一些例子:
字面表示 | 此字面表示可以表示哪些類型的值(在編譯時(shí)刻) |
---|---|
256
|
除了int8和uint8類型外的所有的基本數(shù)值類型。 |
255
|
除了int8類型外的所有的基本數(shù)值類型。 |
-123
|
除了無(wú)符號(hào)整數(shù)類型外的所有的基本數(shù)值類型。 |
123
|
所有的基本數(shù)值類型。 |
123.000
|
|
1.23e2
|
|
'a'
|
|
1.0+0i
|
|
1.23
|
所有浮點(diǎn)數(shù)和復(fù)數(shù)基本數(shù)值類型。 |
0x10000000000000000
(16 zeros)
|
|
3.5e38
|
除了float32和complex64類型外的所有浮點(diǎn)數(shù)和復(fù)數(shù)基本數(shù)值類型。 |
1+2i
|
所有復(fù)數(shù)基本數(shù)值類型。 |
2e+308
|
無(wú)。 |
注意幾個(gè)溢出的例子:
0x10000000000000000
需要65個(gè)比特才能表示,所以在運(yùn)行時(shí)刻,任何基本整數(shù)類型都不能精確表示此字面量。
3.40282346638528859811704183484516925440e+38
,所以3.5e38
不能表示任何float32和complex64類型的值。
1.797693134862315708145274237317043567981e+308
,因此2e+308
不能表示任何基本數(shù)值類型的值。
0x10000000000000000
可以用來(lái)表示float32類型的值,但是它不能被任何float32類型的值所精確表示。上面已經(jīng)提到了,當(dāng)使用字面量來(lái)表示非整數(shù)基本數(shù)值類型的時(shí)候,精度丟失是允許的(但溢出是不允許的)。
更多建議: