第 5 講:數(shù)據(jù)類型(二):字面量和數(shù)據(jù)類型的關(guān)系
Part 1 定義
什么是字面量
在這里示例里,25 這個數(shù)字是我們直接寫到程序代碼里的數(shù)據(jù)信息。這個 25 我們就稱為整數(shù)字面量。
在 C# 的世界里,我們使用的字面量都對應一個“默認的”數(shù)據(jù)類型。換句話說,即使我們左側(cè)的變量不給出數(shù)據(jù)類型的名稱(不管是 BCL 名稱還是關(guān)鍵字),我們總可以通過字面量本身確定變量的類型。
2-1 正整數(shù)字面量
我們可以總結(jié)出如下兩點:
如果是一個整數(shù)字面量的話,那么它默認就是
int
類型的數(shù)據(jù);如果這個數(shù)據(jù)可以用范圍更小的數(shù)據(jù)類型表達出來,那么這個數(shù)值也可以直接自動賦值給這個類型的變量。
下面我們來看一下,這個解釋是什么意思。首先
這個賦值語句下,25 是默認 int
類型的。大家都知道,int
類型和 byte
類型來比較的話,顯然 int
范圍更大;如果將一個能表示出范圍更大的數(shù)據(jù)類型賦值給一個表示范圍較小的數(shù)據(jù)類型,就可能產(chǎn)生錯誤,比如說一個 byte
類型的變量,接受了 300 這個數(shù),顯然就是不合理的。但是我們通過第二點可以得到,顯然例子里的 25 是屬于 byte
類型的數(shù)據(jù)范圍的,所以這樣的賦值語句,編譯器根本不應該告訴你,這是錯誤的賦值。所以,編譯器允許這么賦值。
因此,我通過這則示例告訴你,25 是 int
類型的;而 age
是 byte
類型的,編譯器也允許這么賦值。
當然,25 也可以寫成 +25,因為數(shù)學上的正號加不加都沒關(guān)系,因此 C# 也是一樣。
2-2 負整數(shù)字面量
除了正整數(shù),還有負整數(shù)的字面量。和數(shù)學上的表達完全一致,我們使用減號來表示負數(shù):
這里的 -13
就是負整數(shù)字面量。很有趣的一點是,因為 int
類型的取值范圍是包含負數(shù)的,因此實際上負整數(shù)字面量的默認數(shù)據(jù)類型依然是 int
。而且,它依舊遵循前文提到的“范圍最小賦值原則”(說白了就是前面那一節(jié)內(nèi)容里面的那個第二點)。
2-3 長整數(shù)字面量
C# 的語法是嚴謹?shù)?。由于前文的整?shù)字面量是默認 int
類型的,那么我們就無法直接寫一個超出 int
范圍的整數(shù)字面量。但是 long
類型必須要賦一個初始數(shù)值的話,怎么辦呢?
我們使用后綴字母 L
(或者小寫 l
)來告訴編譯器,這個字面量是 long
類型的。
顯然,這里的 78 億是超出了 int
的取值范圍的(int
最大才到 2147483647),因此如果我們直接寫上 7800000000000 的話,就會出現(xiàn)編譯器錯誤。因此,我們需要強制追加后綴 L
來告訴編譯器,這里的這個數(shù)字是 long
同理,如果數(shù)字為負數(shù),依舊添加負號即可:long p = -1000000000000L
。
另外,這么賦值也是沒問題的:long p = 13L
,但是反過來就不對了:如果右側(cè)是 long
的字面量,而左邊是 int
類型,即使范圍合適,依然不允許賦值(即錯誤賦值):int p = 13L
。這是因為,既然 13 是正常的 int
字面量,那么為什么要追加 L
后綴,然后再賦值給 int
類型呢?這不是就繞了一步嗎?因此編譯器不允許我們這么搞。
2-4 無符號整數(shù)字面量
我們知道,一個整數(shù)字面量是沒辦法確保是不是正整數(shù)的。為了確保字面量本身就可以表示無符號類型,那么就產(chǎn)生了這樣的字面量。
比如,這樣。我們使用 U
字母(或小寫 u
)來表示和暗示這個字面量是 uint
類型的(即無符號整數(shù))。
int
類型,而這里的無符號的整數(shù)字面量默認是 uint
類型的。正是因為這個區(qū)別,因此我們?nèi)缦碌乃姆N組合里,有一種就是不正確的:
int age = 25;
(正確)int age = 25U;
(錯誤)uint age = 25;
(正確)uint age = 25U;
(正確)
這里的 int age = 25U
是錯誤的賦值。因為 int
類型和 uint
類型并不能說“范圍完全兼容”,uint
類型只包含正整數(shù),因此范圍比 int
類型多了一截;而 int
可表示負數(shù),所以 int
可以表達負數(shù)。
顯然,這樣的數(shù)據(jù)類型是無法完整兼容的,因此我們無法通過字面量來把 uint
賦值給 int
類型。
另外,由于無符號字面量本身就是不可負的,因此無符號字面量的前面是不能加負號的。換句話說,-25U
是錯誤的寫法;但是,帶正號可以:+25U
。
最后,U
后綴和 L
后綴是可以混用的。不論你的 U
字母和 L
字母的順序如何,大小寫如何,只要寫在一起作為字面量后綴,就可以表示一個字面量是 ulong
類型的。
同樣地,這里的帶 UL
后綴的字面量也無法賦值給范圍較小類型的其它整數(shù)類型。比如 uint age = 25UL
2-5 浮點數(shù)字面量
浮點數(shù)類型有三種,所以有三種不同的字面量類型。
使用
f
或F
后綴,表示一個小數(shù)是float
類型的;使用
d
或D
后綴,表示一個小數(shù)是double
類型的;使用
m
或M
后綴,表示一個小數(shù)是decimal
類型的;如果任何后綴都沒有的小數(shù)表達式,默認就是
double
類型的。
從精度上和數(shù)據(jù)取值范圍上來說,double
都比起 float
類型要大,因此 float
類型的字面量可以賦值給 double
,但反過來不行:
這樣的賦值里,、g2
和 g3
的賦值是錯誤的。因為 float
類型范圍較小,卻接受了一個 double
類型的字面量。
另外,這里簡單說一下 decimal
類型字面量。decimal
類型的取值范圍比較小,但精度特別高(能精確到 29 位),所以它和 float
還有 double
范圍上并不能直接兼容。和 uint
還有 int
的賦值邏輯一樣,我們不能將 decimal
字面量賦值給 float
或 double
類型的變量;反過來把 float
或 double
類型的字面量賦值給 decimal
類型的變量也不可以。
這里,后面四種賦值全部都是錯誤的。
0.37
可以寫成.37
;但是小數(shù)部分就算為 0,也不能省略:30.0
不能寫30.
,這個寫法 C 語言允許,但 C# 里不行。
2-6 整數(shù)和浮點數(shù)
前面我們一直說的是整數(shù)和小數(shù)的字面量,但它們沒有互相賦值。
思考一下,decimal d = 30U;
會不會成功呢?C# 里規(guī)定,所有前文提到的字面量全部都可以通過賦值的方式賦值給任何浮點數(shù)類型,但反過來的話,任何浮點數(shù)類型的數(shù)據(jù)都不可以賦值給任何整數(shù)的數(shù)據(jù)類型。因為浮點數(shù)的范圍我們沒有在前文里提及,因此我們無法介紹這一點。
大概來說,
float
這個最大可以到大約 10 的 38 次方(再怎么說都超出ulong
最大的整數(shù)的數(shù)據(jù)取值范圍了),double
能達到大約 10 的 308 次方,而decimal
的最大值大約是 。所以范圍上來說,最小范圍的float
類型,也可以完美覆蓋任何整數(shù)數(shù)據(jù)類型的數(shù)據(jù),因此,用浮點數(shù)類型的變量接受整數(shù)類型的字面量,是怎么都允許的;但反過來因為數(shù)據(jù)的取值范圍不兼容的緣故,這樣就不行了。稍微啰嗦一下,30 和 30.0 的區(qū)別是,在 C# 里,30 是整數(shù)(
int
字面量),而 30.0 是浮點數(shù)(double
字面量)。因此,double d = 30
、double d = 30.0
和double d = 30D
的賦值意義不太一樣。后面兩種是同樣的模式(因為都是double
類型字面量),而第一個則是通過“浮點數(shù)接受整數(shù)類型的變量”這個規(guī)則而賦值的。
2-7 科學計數(shù)法字面量
為了保證數(shù)據(jù)能夠簡單表達,C# 允許使用科學計數(shù)法類似的寫法來表達一個浮點數(shù)。舉個例子:
在這里例子里,1E5
稱為科學計數(shù)法??茖W計數(shù)法的表達規(guī)則是這樣的:如果一個數(shù)學上的科學計數(shù)法表達是?a * 10 的?b 次方?
部分使用字母
E
或e
代替;a 和 b 則按照科學計數(shù)法的基本寫法即可。
比如 1E5 就是 10 的 5 次方。當然,如果 b 是負數(shù)的話,科學計數(shù)法里這樣表達的數(shù)據(jù)就是一個小數(shù)了。比如 1E-3
就是 10 的 -3 次方,即 1/1000(0.001)。
2-8 字符和字符串的字面量
因為這一個內(nèi)容牽扯到字符串的使用,因此這里我們不作介紹,我們在下一節(jié)就會介紹它們。
2-9 布爾型字面量
最后還剩下布爾型數(shù)據(jù)的字面量沒有說了。因為布爾型只用來表示對錯,所以只有真(True)和假(False)兩個結(jié)果。在 C# 里,直接采用 true
和 false
這兩個關(guān)鍵字就可以充當了。
就是這樣的。前面的文章其實就已經(jīng)說過了,不過這里再說一下。這里的 true
和 false
是布爾型里唯有的兩個字面量。
另請注意,因為它只表示對錯,因此跟整數(shù)、浮點數(shù)完全沒有關(guān)聯(lián),因為我們無法把布爾型數(shù)據(jù)賦值給任何浮點數(shù)數(shù)據(jù)類型和任何整數(shù)數(shù)據(jù)類型;反之亦然。
這兩種賦值都是錯的。bool
字面量只能賦值給 bool
Part 3 總結(jié)
我相信你根本記不住前面的東西。所以我這里做一個簡要的回顧和歸納。
3-1 字面量默認類型
整數(shù)字面量默認是
int
類型的(不論帶不帶正負號,都是int
類型的);帶
L
后綴(或l
)的整數(shù)字面量是long
類型的(不論帶不帶正負號);帶
U
后綴(或u
)的整數(shù)字面量是uint
類型的(這樣的話,只能帶正號,或者不要符號);同時帶有
U
和L
后綴的整數(shù)字面量是ulong
類型的(這兩個后綴記號不需要考慮先后順序,也不需要考慮大小寫);帶
F
或f
后綴的字面量是float
類型的;帶
D
或d
后綴(或不帶后綴的小數(shù))的字面量是double
類型的;帶
M
或m
后綴的字面量是decimal
類型的;科學計數(shù)法字面量默認是
double
類型的;bool
字面量只有兩個:true
和false
,且均使用關(guān)鍵字表示。
3-2 字面量賦值關(guān)系
所有字面量的默認類型,可以直接賦值給這個類型的變量;
不帶后綴的整數(shù)字面量是可以允許在兼容范圍的時候,賦值給較小數(shù)據(jù)類型的變量;
帶后綴的整數(shù)字面量,不能賦值給范圍較小的變量(不論是否兼容取值范圍);
double
類型的變量能接受float
字面量和double
類型的字面量的賦值,但反之不然;decimal
類型的變量只能接受decimal
字面量,其它的浮點數(shù)字面量都不可以;任何整數(shù)類型的字面量均可以直接賦值給任何浮點數(shù)類型,但反之不然;
由于科學計數(shù)法是
double
類型的字面量,所以它的賦值規(guī)則和double
字面量的規(guī)則是一樣的;bool
字面量不能賦值給其它任何類型的變量,反之亦然。