Swift定製化構造過程
定製化構造過程
你可以通過輸入參數和可選屬性類型來定製構造過程,也可以在構造過程中修改常量屬性。這些都將在後面章節中提到。
構造參數
你可以在定義構造器時提供構造參數,爲其提供定製化構造所需值的類型和名字。構造器參數的功能和語法跟函數和方法參數相同。
下面例子中定義了一個包含攝氏度溫度的結構體Celsius
。它定義了兩個不同的構造器:init(fromFahrenheit:)
和init(fromKelvin:)
,二者分別通過接受不同刻度表示的溫度值來創建新的實例:
struct Celsius {
var temperatureInCelsius: Double = 0.0
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius 是 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius 是 0.0」
第一個構造器擁有一個構造參數,其外部名字爲fromFahrenheit
,內部名字爲fahrenheit
;第二個構造器也擁有一個構造參數,其外部名字爲fromKelvin
,內部名字爲kelvin
。這兩個構造器都將唯一的參數值轉換成攝氏溫度值,並保存在屬性temperatureInCelsius
中。
內部和外部參數名
跟函數和方法參數相同,構造參數也存在一個在構造器內部使用的參數名字和一個在調用構造器時使用的外部參數名字。
然而,構造器並不像函數和方法那樣在括號前有一個可辨別的名字。所以在調用構造器時,主要通過構造器中的參數名和類型來確定需要調用的構造器。正因爲參數如此重要,如果你在定義構造器時沒有提供參數的外部名字,Swift 會爲每個構造器的參數自動生成一個跟內部名字相同的外部名,就相當於在每個構造參數之前加了一個哈希符號。
注意:
如果你不希望爲構造器的某個參數提供外部名字,你可以使用下劃線_
來顯示描述它的外部名,以此覆蓋上面所說的默認行爲。
以下例子中定義了一個結構體Color
,它包含了三個常量:red
、green
和blue
。這些屬性可以存儲0.0到1.0之間的值,用來指示顏色中紅、綠、藍成分的含量。
Color
提供了一個構造器,其中包含三個Double
類型的構造參數:
struct Color {
let red = 0.0, green = 0.0, blue = 0.0
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
}
每當你創建一個新的Color
實例,你都需要通過三種顏色的外部參數名來傳值,並調用構造器。
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
注意,如果不通過外部參數名字傳值,你是沒法調用這個構造器的。只要構造器定義了某個外部參數名,你就必須使用它,忽略它將導致編譯錯誤:
let veryGreen = Color(0.0, 1.0, 0.0)
// 報編譯時錯誤,需要外部名稱
可選屬性類型
如果你定製的類型包含一個邏輯上允許取值爲空的存儲型屬性--不管是因爲它無法在初始化時賦值,還是因爲它可以在之後某個時間點可以賦值爲空--你都需要將它定義爲可選類型optional type
。可選類型的屬性將自動初始化爲空nil
,表示這個屬性是故意在初始化時設置爲空的。
下面例子中定義了類SurveyQuestion
,它包含一個可選字符串屬性response
:
class SurveyQuestion {
var text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
println(text)
}
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?") cheeseQuestion.ask() // 輸出 "Do you like cheese?" cheeseQuestion.response = "Yes, I do like cheese.
調查問題在問題提出之後,我們才能得到回答。所以我們將屬性回答response
聲明爲String?
類型,或者說是可選字符串類型optional String
。當SurveyQuestion
實例化時,它將自動賦值爲空nil
,表明暫時還不存在此字符串。
構造過程中常量屬性的修改
只要在構造過程結束前常量的值能確定,你可以在構造過程中的任意時間點修改常量屬性的值。
注意:
對某個類實例來說,它的常量屬性只能在定義它的類的構造過程中修改;不能在子類中修改。
你可以修改上面的SurveyQuestion
示例,用常量屬性替代變量屬性text
,指明問題內容text
在其創建之後不會再被修改。儘管text
屬性現在是常量,我們仍然可以在其類的構造器中修改它的值:
class SurveyQuestion {
let text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
println(text)
}
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// 輸出 "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)