- Swift細致入門與最佳實踐
- 陳強
- 4671字
- 2019-10-21 15:55:16
2.4 常量和變量
Swift語言中的基本數據類型,按其取值可以分為常量和變量兩種。在程序執行過程中,其值不發生改變的量被稱為常量,其值可變的量被稱為變量。兩者可以和數據類型結合起來進行分類,例如可以分為整型常量、整型變量、浮點常量、浮點變量、字符常量、字符變量、枚舉常量、枚舉變量。在C語言程序中,常量是可以不經說明而被直接引用的,而變量則必須先定義后使用。在本節的內容中,將對常量和變量的知識進行深入講解。
2.4.1 聲明常量
不管是什么語言,變量都必須確定數據類型,否則不能存儲數據。但不同的語言,獲取數據類型的方式是有區別的。例如,對于靜態語言(Java、C#等),必須在定義變量時指定其數據類型。當然,為了讓這個變量什么類型的值都能存儲,也可以將變量類型設置為Object或相似的類型。但不管設置為什么,類型是必須要指定一個的。所以,靜態語言變量的數據類型是在編譯時確定的。
在Swift語言中,在使用常量和變量前必須聲明,使用關鍵字“let”來聲明常量,使用關鍵字“var”來聲明變量。
在Swift語言中,使用關鍵字let聲明常量,具體語法格式如下所示。
let name=value
(1)name:表示常量的名字,在命名時建議遵循如下規則。
變量名首字母必須為字母(小寫a-z,大寫A-Z)或下畫線“_”開始;
常量名之間不能包含空格。
(2)value:常量的值。
例如在下面的演示代碼中,展示了用常量和變量來記錄用戶嘗試登錄次數的方法。
let mm=10
var nn=0
在上述代碼中,聲明一個名為“mm”的新常量,并且將其賦值為10。然后,聲明一個名為“nn”的變量,并且將其值初始化為0。這樣,允許的最大嘗試登錄次數被聲明為一個常量,因為這個值不會改變。當前嘗試登錄次數被聲明為一個變量,因為每次嘗試登錄失敗時都需要增加這個值。
對于常量來說,不管指定不指定數據類型,都必須進行初始化。例如,下面兩條語句都是不合法的。
let const1 //不合法,常量必須初始化
let const2:Int //不合法,常量必須初始化
要想定義一個合法的常量,必須使用下面的形式。
let const3:Int=20 //合法的常量定義(指定數據類型)
let const3=20 //合法的常量定義(不指定數據類型,動態推導)

實例文件main.swift的具體實現代碼如下所示。

本實例執行后的效果如圖2-1所示。

圖2-1 執行效果
注意:Swift的編程風格
(1)常量通過let關鍵字定義,而變量使用var關鍵字定義。任何值如果是一個不變量,那么請使用let關鍵字恰如其分地定義它,最后你會發現自己喜歡使用let遠多于far。
(2)有一個方法可以幫開發者符合該項規則,將所有值都定義成常量,然后編譯器提示時將其改為變量。
2.4.2 聲明變量
對于動態語言來說,變量也必須要有一個數據類型,只是這個數據類型并不是在定義變量時指定的,而是在程序運行到變量第一次初始化的語句時才確定數據類型。所以,動態語言的變量數據類型是在程序運行時確定的,這也是這種語言被稱為動態語言的原因之一。
在Swift語言中,其值可以改變的量被稱為變量。一個變量應該有一個名字,在內存中占據一定的存儲單元。變量定義必須放在變量使用之前,一般放在函數體的開頭部分。可以在Swift程序的同一行代碼中聲明多個常量或者多個變量,之間用逗號“,”隔開。例如下面的演示代碼。
var x=0.0,y=0.0,z=0.0
var m=10,n=2134,q=12345
在Swift語言中,如果在代碼中有不需要改變的值,則需要使用關鍵字“let”將其聲明為常量,將需要改變的值聲明為變量。
無論是變量還是常量,一旦確定了數據值類型,便不能改變。例如,下面的代碼會拋出編譯錯誤。
var value="abc"
value=20
在上述代碼中,value已經確定了是字符串(String)類型,不能再次被定義為Int類型。
除此之外還要注意,如果變量或常量在定義時未指定數據類型,初始化什么值都可以。一旦指定了數據類型,必須初始化與數據類型相符的值。例如,下面的代碼是錯誤的。
var value:String=123 //必須初始化字符串值
如果想使用一個var或let定義多個變量或常量,可以用逗號“,”分隔多個變量或常量。例如,下面定義的變量和常量都是合法的。
var v1="abc",v2:Float=20.12,v3:Bool
let const1="xyz",const2:Double=12.34;
在Swift程序中,聲明根據變量類型和值的不同有著不同的形式,例如,存儲型變量和屬性,計算型變量和屬性,存儲型變量監視器和屬性監視器,類和靜態變量屬性等,所使用的聲明形式取決于變量所聲明的范圍和打算聲明的變量類型。
(1)聲明存儲型變量和存儲型屬性
在Swift語言中,通過如下所示的格式聲明一個存儲型變量或存儲型變量屬性。
var name:type=expression
在上述格式中,“name”表示聲明的標量名字,“type”表示聲明的變量的類型,“expression”表示具體的變量值描述。在Swift語言中,可以使用上述格式在全局、函數、類和結構體的聲明(context)中聲明一個變量,具體說明如下所示。
當以上述形式在全局或者一個函數內聲明變量時,聲明的變量代表的是一個存儲型變量。
當在類或者結構體中被聲明時,聲明的變量代表的是一個存儲型變量屬性。
初始化的表達式不可以在協議(protocol)定義中出現,在其他情況下的初始化表達式是可選的。如果沒有初始化表達式,那么在定義變量時必須顯示的聲明變量類型(:type)。
正如名字一樣,存儲型變量的值或存儲型變量屬性均存儲在內存中。

實例文件main.swift的具體實現代碼如下所示。

本實例執行后的效果如圖2-2所示。

圖2-2 執行效果
(2)計算型變量和計算型屬性
在Swift語言中,通過如下所示的格式聲明一個存儲型變量或存儲型屬性。

在Swift程序中,可以使用上述格式在全局、函數體、類、結構體、枚舉和擴展中聲明一個變量。具體說明如下所示。
當變量以這種形式在全局或者一個函數內被聲明時,聲明的變量代表一個計算型變量。
當在類、結構體、枚舉、擴展的上下文中被聲明時,聲明的變量代表一個計算型變量屬性。
getter用來讀取變量值,setter用來寫入變量值。setter子句是可選擇的,而getter是必需的。在實際應用中可以將這些語句全部省略,只是簡單的直接返回請求值。但是setter語句和getter語句必須成對出現,如果提供了一個setter語句,也必須提供一個getter語句。
setter的名字和圓括號內的語句是可選的。如果設置了一個setter名,它就會作為setter的參數被使用。
和存儲型變量和存儲型屬性不同,計算型屬性和計算型變量的值不存儲在內存中。
(3)存儲型變量監視器和屬性監視器
在Swift語言中,可以使用willset和didset監視器來聲明一個存儲型變量或屬性。聲明一個包含監視器的存儲型變量或屬性的語法格式如下所示。

在Swift程序中,可以使用上述格式在全局、函數體、類、結構體、枚舉、擴展中聲明一個變量。具體說明如下所示。
當變量以上述格式在全局或者一個函數內被聲明時,監視器代表一個存儲型變量監視器。
當在類、結構體、枚舉、擴展中被聲明變量時,監視器代表屬性監視器。
可以為適合的監視器添加任何存儲型屬性,也可以通過重寫子類屬性的方式為適合的監視器添加任何繼承的屬性(無論是存儲型還是計算型的)。
初始化表達式在類或者結構體的聲明中是可選的,但是在其他地方是必需的。無論在什么地方聲明,所有包含監視器的變量聲明都必須有類型注釋(Type Annotation)。
當改變變量或屬性的值時,willset和didset監視器提供了一個監視的方法(適當的回應)。監視器不會在變量或屬性第一次初始化時運行,只有在值被外部初始化語句改變時才會被運行。
willset監視器只有在變量或屬性值被改變之前運行。新的值作為一個常量經過willset監視器,因此不可以在willset語句中改變它。didset監視器在變量或屬性值被改變后立即運行。和willset監視器相反,為了以防止仍然需要獲得舊的數據,舊變量值或者屬性會經過didset監視器。這表示如果在變量或屬性自身的didiset監視器語句中設置了一個值,設置的新值會取代在willset監視器中經過的那個值。
在willset和didset語句中,setter名和圓括號的語句是可選的。如果設置了一個setter名,它就會作為willset和didset的參數被使用。如果不設置setter名,willset監視器初始名為newvalue,didset監視器初始名為oldvalue。
當提供一個willset語句時,didset語句是可選的。同樣道理,當提供一個didset語句時,willset語句是可選的。
(4)類和靜態變量屬性
在Swift語言中,使用class關鍵字用來聲明類的計算型屬性,使用static關鍵字用來聲明類的靜態變量屬性。
注意:在大多數靜態語言中,指定整數或浮點數會確認默認的類型。例如,在Java語言中,如果直接寫23,會認為23是int類型;如果要讓23變成long類型,則需要使用23L。如果直接寫23.12,編譯器會認為23.12是double類型,如果要將23.12變成float類型,需要使用23.12f。而對于float v=23.12;,Java編譯器會認為是錯誤的,因為23.12是double,而不是float,正確的寫法是float v=23.12f。而對于short value=23是正確的。因為Java編譯器會自動將23轉換為short類型,但23必須在short類型的范圍內。這么做是因為在byte code中byte、short、int都是使用同一個指令,而float和double使用了不同的指令,所以浮點數沒有自動轉換(理論上是可以的)。在Swift語言中,浮點數會自動轉換,所以var v:Float=20.12是沒問題的。
2.4.3 輸出常量和變量
在Swift語言中,可以用函數println來輸出當前常量或變量的值。例如如下所示的演示代碼。

在Swift語言中,println是一個用來輸出的全局函數,輸出的內容會在最后換行。如果使用Xcode,println將會輸出內容到“console”面板上。另一種函數稱為print,唯一區別是在輸出內容最后不會換行。
例如在下面的演示代碼中,println函數會輸出傳入的String值。
print("This is a string")
//輸出"This is a string"
與Cocoa中的函數NSLog類似,函數println可以輸出更復雜的信息,這些信息可以包含當前常量和變量的值。
在Swift語言中,使用字符串插值(string interpolation)的方式將常量名或者變量名當作占位符加入長字符串中。Swift會用當前常量或變量的值替換這些占位符,將常量或變量名放入圓括號中,并在括號前使用反斜杠將其轉義。例如如下所示的演示代碼。

注意:字符串插值所有可用的選項,請參考字符串插值。

實例文件main.swift的具體實現代碼如下所示。

本實例執行后的效果如圖2-3所示。

圖2-3 執行效果
2.4.4 標注類型
在Swift語言中,在聲明常量或者變量時可以添加類型標注(Type annotation),用以說明常量或者變量中要存儲的值的類型。當在程序中添加類型標注時,需要在常量或者變量名后添加一個冒號和空格,然后添加類型名稱。
例如在下面的代碼中,為變量welcomeMessage標注了類型,表示這個變量可以存儲String類型的值。
var welcomeMessage:String
聲明中的冒號代表著“是…類型”,所以這行代碼可以被理解為:
“聲明一個類型為String,名字為welcomeMessage的變量。”
“類型為String”是指“可以存儲任意String類型的值。”
此時變量welcomeMessage可以被設置成任意字符串,例如如下所示的演示代碼。
welcomeMessage="Hello"
在Swift編程應用中,一般很少需要用到類型標注。如果在聲明常量或者變量時賦了一個初始值,Swift可以推斷出這個常量或者變量的類型,具體方法請參考本書后面的類型安全和類型推斷章節的內容。在上面的演示代碼中,因為沒有為變量welcomeMessage賦初始值,所以變量welcomeMessage的類型是通過一個類型標注指定的,而不是通過初始值推斷的。
注意:從Xcode6 Beta4版本開始,多個相關變量可以用“類型標注”(type annotaion)在同一行中聲明為同一類型。

實例文件main.swift的具體實現代碼如下所示。

本實例執行后的效果如圖2-4所示。

圖2-4 執行效果
2.4.5 常量和變量的命名規則
在Swift語言中,可以用任何喜歡的字符作為常量和變量名,這其中也包括Unicode字符。例如如下所示的演示代碼。

在Swift語言中,常量與變量名不能包含如下所示的元素。
數學符號。
箭頭。
保留的(或者非法的)Unicode碼位。
連線。
制表符。
不能以數字開頭,但是可以在常量與變量名的其他地方包含數字。
一旦將常量或者變量聲明為確定的類型,那么就不能使用相同的名字再次進行聲明,或者改變其存儲的值的類型。另外,也不能將常量與變量進行互轉。
注意:如果需要使用與Swift保留關鍵字相同的名稱作為常量或者變量名,必須使用反引號“`”將關鍵字包圍并將其作為名字使用。盡管如此,建議讀者開始應當避免使用關鍵字作為常量或變量名,除非別無選擇。
在Swift語言中,可以修改現有的變量值為其他同類型的值,例如在下面的演示代碼中,將變量friendlyWelcome的值從“Hello!”改為了“mm!”。


實例文件main.swift的具體實現代碼如下所示。


本實例執行后的效果如圖2-5所示。

圖2-5 執行效果
與變量不同,常量的值一旦被確定就不能更改了。如果對常量嘗試進行上述修改操作,就會發生編譯報錯的情形。例如如下所示的演示代碼。

- INSTANT Mock Testing with PowerMock
- Oracle WebLogic Server 12c:First Look
- Processing互動編程藝術
- Mastering C# Concurrency
- Hands-On JavaScript High Performance
- Rust Cookbook
- Nginx Essentials
- Python:Deeper Insights into Machine Learning
- Python大學實用教程
- 汽車人機交互界面整合設計
- Java程序設計教程
- Clojure Polymorphism
- Modular Programming with JavaScript
- Ionic3與CodePush初探:支持跨平臺與熱更新的App開發技術
- Microsoft Dynamics GP 2013 Cookbook