第 4 講:數(shù)據(jù)類型(一):數(shù)據(jù)類型簡(jiǎn)要介紹
本節(jié)給大家介紹一下 C# 的數(shù)據(jù)類型,以及變量聲明的方式和用法。
Part 1 讓我們先來(lái)學(xué)習(xí)一下基本的用法
數(shù)據(jù)類型(Data Type)是為了規(guī)范化管理所有世間萬(wàn)物編程寫入代碼的時(shí)候,進(jìn)行處理的一種體系。如果沒有數(shù)據(jù)類型這個(gè)概念,可能就會(huì)像是 Python 那樣,編譯期間無(wú)法察覺任何數(shù)據(jù)的問(wèn)題;而在運(yùn)行的時(shí)候才會(huì)知道,“Shoot,數(shù)據(jù)計(jì)算的時(shí)候出錯(cuò)了”。
數(shù)據(jù)類型,是把世間萬(wàn)物以編程的視角定義出來(lái)的一種“屬相”。比如說(shuō)買菜的單價(jià),是小數(shù)類型的(因?yàn)榭梢跃_到毛和分);再比如說(shuō)排隊(duì)人數(shù),是整數(shù)類型的(嚴(yán)格來(lái)說(shuō)是正整數(shù)類型的)。我們通過(guò)這樣的機(jī)制,來(lái)表述一個(gè)事物的確切數(shù)量或者數(shù)據(jù)的具體大小。
用來(lái)臨時(shí)傳達(dá)和表示數(shù)據(jù)大小的手段,就是變量(Variable)。比如下面的這段代碼,就是通過(guò)定義變量,表示一個(gè)指定的數(shù)據(jù),然后顯示在屏幕上的過(guò)程:
首先,我們來(lái)說(shuō)明一下,每一個(gè)數(shù)據(jù)都是表達(dá)什么。首先,我們前面說(shuō)過(guò),程序的整體執(zhí)行順序是從第 7 行開始,到第 12 行結(jié)束,那么我們一行一行來(lái)看:
第 7 行寫的是 string dogName = "Shiny";
,這句話的意思是,定義了一個(gè)叫做 dogName
的變量。dogName
是我們隨手寫的名稱。顯然它并不是 C# 語(yǔ)法規(guī)定的成分,因此它是一個(gè)標(biāo)識(shí)符。
既然是標(biāo)識(shí)符,那么必然需要滿足標(biāo)識(shí)符的書寫規(guī)范和規(guī)則:數(shù)字、字母、下劃線和 @
的組合,首字符不能是數(shù)字;后面的字母里不能有 @
,等等。顯然,dogName
是符合取名的要求的,因此是一個(gè)正確的標(biāo)識(shí)符。從英語(yǔ)本身的角度來(lái)說(shuō),dogName
的實(shí)際意思就是“狗狗的名字”。是的,后面我們直接寫上了 "Shiny"
,這個(gè)以雙引號(hào)引起來(lái)的東西,我們稱為字符串字面量(String Literal)。我們通過(guò)等號(hào) =
來(lái)將右側(cè)的這個(gè)字面量賦值給(Assignment),從人類可以理解的邏輯來(lái)看,你可以把 dogName
當(dāng)成一個(gè)箱子,這個(gè) "Shiny"
就是箱子里裝的東西。賦值語(yǔ)句(string dogName = "Shiny";
)的過(guò)程就是把這個(gè)東西裝進(jìn)箱子。
我們稍微注意一下,dogName
前面有一個(gè) string
。這就是 dogName
的數(shù)據(jù)類型:string 的意思是“串”,比如英語(yǔ)里的 a string of(一串……)。在這里,string
被認(rèn)為是一個(gè)關(guān)鍵字。它的作用就是用來(lái)聲明一個(gè)變量是“串”類型的。所謂的數(shù)據(jù)類型“串”,就是用來(lái)表示“原封不動(dòng)的數(shù)據(jù)序列”。它們直接用雙引號(hào)寫出來(lái),然后通過(guò)賦值的形式給到變量上去。
同樣地,我們可以得到第 8 行和第 9 行類似的理解方式:定義一個(gè) int
和 double
類型的變量為 age
和 price
,然后分別賦值 5
和 299.98D
。首先,299.98D
的字母 D
是可以不寫的,即 299.98
,那么就是一個(gè)很普通的小數(shù);而 5
則是一個(gè)很普通的整數(shù)。然后,分別通過(guò)賦值語(yǔ)句進(jìn)行賦值。
最后我們來(lái)看一下第 11、12 行。第 11 行是我們前文介紹過(guò)的 Console.WriteLine
方法。這個(gè)過(guò)程用來(lái)輸出顯示一行文字到屏幕上。不過(guò)這里有所變化,因?yàn)樵谑褂煤惋@示內(nèi)容的時(shí)候,后面還使用逗號(hào)分隔了 dogName
和 age
。細(xì)心一點(diǎn)可以看到,整個(gè)輸出內(nèi)容里,有兩處大括號(hào)和數(shù)字編號(hào)構(gòu)成的占位符(Placeholder)。占位符最后會(huì)被后面的變量的數(shù)據(jù)以對(duì)位的形式替換掉。比如說(shuō),{0}
對(duì)應(yīng)第一個(gè)逗號(hào)分隔的變量 dogName
,而 {1}
就對(duì)應(yīng)第二個(gè)逗號(hào)分隔的變量 age
。
占位符的作用就是體現(xiàn)在 Console.WriteLine
里,用來(lái)被逗號(hào)分隔的變量作替換的。按照 C# 語(yǔ)法的約定,占位符的編號(hào)(0、1、2 這些)可以重復(fù)使用,但必須從 0 開始編號(hào)。比如說(shuō)
這里的 {0}
被 "years old"
{1}
則被 30
替換,{2}
被 40 替換,所以輸出內(nèi)容就是
I'm 30 years old, while she is 40 years old.
大概就是這么一個(gè)感覺。
順帶一提,第 10 行沒有東西,我們把這種“單純是為了排版好看,為了分清執(zhí)行邏輯部分”的空白行稱為空行
最后,前面示例最終的顯示結(jié)果是這樣的:
The dog's name is Shiny, 5 years old.
When I bought her home, the price is 299.98.
再順帶一提,int
和 double
在 C# 里分別表示整數(shù)和小數(shù)。整數(shù)和小數(shù)在 C# 里分得非常細(xì)致,所以并不是只有 int
就表示整數(shù)類型,也并不是只能用 double
來(lái)表示小數(shù)。下面我們就來(lái)看一下,C# 預(yù)定義的數(shù)據(jù)類型。
在 C# 的世界里,規(guī)定了許多基本的數(shù)據(jù)類型。我們都來(lái)看一看。

整個(gè)表格根本不需要背下來(lái)。畢竟不是考試。你只需要知道,什么是無(wú)符號(hào)、什么是二進(jìn)制小數(shù)、什么是十進(jìn)制小數(shù)、什么是布爾就可以了。
無(wú)符號(hào)(Unsigned)和帶符號(hào)ushort
作為最合適的數(shù)據(jù)類型來(lái)表示:ushort popularity = 3000;
。
你可能會(huì)問(wèn)我,我選 int
不是也可以?反正 int
范圍那么大,3000 肯定是在其中的。是的,你沒有說(shuō)錯(cuò)。也正是因?yàn)檫@個(gè)原因,前文說(shuō)的是“我們應(yīng)當(dāng)選取”,而不是“我們必須選取”。只要我們預(yù)估的數(shù)據(jù)的可能取值在一個(gè)指定范圍內(nèi)的話,就隨便你怎么選都 OK。所以,int popularity = 3000;
是沒有問(wèn)題的;但是,如果你寫 byte popularity = 3000;
必然是錯(cuò)誤的。
接著說(shuō)一下浮點(diǎn)數(shù)(Floating-point Number)。在計(jì)算機(jī)的世界里,浮點(diǎn)數(shù)其實(shí)就是小數(shù)的官方說(shuō)法。因?yàn)樵谟?jì)算機(jī)的內(nèi)部,小數(shù)是通過(guò)科學(xué)計(jì)數(shù)法表達(dá)的,因此小數(shù)點(diǎn)就變成了漂浮不定的了,因而稱為浮點(diǎn)數(shù)(小數(shù)點(diǎn)漂浮不定的數(shù)字)。
小數(shù)在計(jì)算機(jī)里有兩種表達(dá)模型,一種叫二進(jìn)制小數(shù)(Binary Floating-point),一種則是十進(jìn)制小數(shù)(Decimal Floating-point)。二進(jìn)制小數(shù)就是將小數(shù)用 的方式表達(dá)出來(lái);而十進(jìn)制小數(shù)就是 了。別看只是 2 和 10 變了,實(shí)際上數(shù)據(jù)的存儲(chǔ)精度也會(huì)變化。
在學(xué)習(xí)小數(shù)的二進(jìn)制表達(dá)的時(shí)候,我們知道,很多小數(shù)在十進(jìn)制下是精確的,但表示成二進(jìn)制之后,小數(shù)就不再精確了;相反,它們?cè)诙M(jìn)制表達(dá)下,反而變成了無(wú)限循環(huán)小數(shù)。因?yàn)橛?jì)算機(jī)存儲(chǔ)機(jī)制的限制,這些數(shù)據(jù)不能精確存儲(chǔ),“無(wú)限循環(huán)小數(shù)”直接被截?cái)?/strong>(Truncate)為“有限小數(shù)”,因而數(shù)據(jù)本身都發(fā)生變化了,所以就不精確了。
我們無(wú)需了解底層存儲(chǔ)浮點(diǎn)數(shù)的方式(如果確實(shí)需要了解相關(guān)內(nèi)容,請(qǐng)參看 IEEE 754 規(guī)范),所以只需要知道浮點(diǎn)數(shù)是不精確的就行了。
浮點(diǎn)數(shù)一共有三種,它們的范圍也有一些區(qū)別,最小的是 float
,能精確大約 6 位有效數(shù)字;double
則大約能到 12 位有效數(shù)字;decimal
則精度更高(甚至能達(dá)到 28 位左右)。但是,它們范圍最小都能表達(dá)到 10 的 38 次方,所以完全不用擔(dān)心運(yùn)算超出數(shù)據(jù)范圍。由于從使用上來(lái)說(shuō),三種數(shù)據(jù)類型只有精度和數(shù)據(jù)范圍的區(qū)別,實(shí)際上沒別的區(qū)別,因此這里就不作很細(xì)的區(qū)分了;如果用到了確實(shí)需要講的區(qū)別,我們會(huì)在后續(xù)內(nèi)容里說(shuō)明。
布爾(Boolean)類型說(shuō)白了就是我們平時(shí)生活中用來(lái)回答“對(duì)”和“錯(cuò)”的這兩個(gè)數(shù)值。“對(duì)”在 C# 里用關(guān)鍵字 true
表示,而“錯(cuò)”就用的是關(guān)鍵字 false
表示。比如說(shuō):
大概是這么一種感覺。當(dāng)然,從另外一個(gè)角度來(lái)說(shuō),布爾型數(shù)據(jù)的數(shù)據(jù)取值范圍只有這兩個(gè)數(shù)值;但別看只有這兩個(gè)取值,但它的用處很多,也很重要,以后在講解條件、循環(huán)結(jié)構(gòu)的時(shí)候,會(huì)廣泛使用布爾型數(shù)據(jù)。
然后看到表格,稍微注意一下的是,字節(jié)型數(shù)據(jù)和帶符號(hào)字節(jié)型,以及其它的整數(shù)類型是有區(qū)別的:字節(jié)型數(shù)據(jù)是默認(rèn)無(wú)符號(hào)的,要使用帶有負(fù)數(shù)的范圍的字節(jié)型數(shù)據(jù),需要追加 s 字母(signed 這個(gè)單詞);而其它的整數(shù)默認(rèn)就是帶符號(hào)的(有負(fù)數(shù)范圍的),需要使用無(wú)符號(hào)的類型,則需要追加 u 字母(unsigned 單詞)。
Part 3 基礎(chǔ)類庫(kù)名
前文提到的這些數(shù)據(jù)類型,除了使用前面的關(guān)鍵字作為類型名稱以外,還可以使用全稱。可以從前面的表格里看到,它們的全稱都帶“System.”。是不是很眼熟?是的,這就是我們之前說(shuō) Console
的時(shí)候,需要引入的命名空間。是的,所有這些類型都是系統(tǒng)自帶的,因此全部被包含在 System
命名空間下。如果你使用它們,要么直接使用關(guān)鍵字,要么寫全稱。寫全稱就需要你先寫上 using System;
才可以使用它們。
它們是等價(jià)的兩種寫法,唯一的區(qū)別就是,全稱寫法需要引入 System
;而 int
這類關(guān)鍵字的話,直接用,不用寫引用指令,系統(tǒng)會(huì)自動(dòng)追加 using System;
這一條指令。
哦對(duì)了,這些數(shù)據(jù)類型的全稱,我們稱為基礎(chǔ)類庫(kù)(Basic Class Library,簡(jiǎn)稱 BCL)名稱。
Part 4 總結(jié)
本節(jié)內(nèi)容給大家做了一個(gè)基本的數(shù)據(jù)類型的介紹,還說(shuō)了變量的聲明方式,以及使用的方式(通過(guò)占位符和 Console.WriteLine
方法配套使用)。
下一節(jié)內(nèi)容,我們會(huì)繼續(xù)探討數(shù)據(jù)類型。因?yàn)椤置媪浚€有字符、字符串類型我們都還沒說(shuō)呢。