位置:首頁 > 高級語言 > Swift教學 > Swift值類型的構造器代理

Swift值類型的構造器代理

值類型的構造器代理

構造器可以通過調用其它構造器來完成實例的部分構造過程。這一過程稱為構造器代理,它能減少多個構造器間的代碼重複。

構造器代理的實現規則和形式在值類型和類類型中有所不同。值類型(結構體和枚舉類型)不支持繼承,所以構造器代理的過程相對簡單,因為它們隻能代理任務給本身提供的其它構造器。類則不同,它可以繼承自其它類(請參考繼承),這意味著類有責任保證其所有繼承的存儲型屬性在構造時也能正確的初始化。這些責任將在後續章節類的繼承和構造過程中介紹。

對於值類型,你可以使用self.init在自定義的構造器中引用其它的屬於相同值類型的構造器。並且你隻能在構造器內部調用self.init

注意,如果你為某個值類型定義了一個定製的構造器,你將無法訪問到默認構造器(如果是結構體,則無法訪問逐一對象構造器)。這個限製可以防止你在為值類型定義了一個更複雜的,完成了重要準備構造器之後,彆人還是錯誤的使用了那個自動生成的構造器。


注意:
假如你想通過默認構造器、逐一對象構造器以及你自己定製的構造器為值類型創建實例,我們建議你將自己定製的構造器寫到擴展(extension)中,而不是跟值類型定義混在一起。想查看更多內容,請查看擴展章節。
 

下麵例子將定義一個結構體Rect,用來展現幾何矩形。這個例子需要兩個輔助的結構體SizePoint,它們各自為其所有的屬性提供了初始值0.0

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}

你可以通過以下三種方式為Rect創建實例--使用默認的0值來初始化originsize屬性;使用特定的originsize實例來初始化;使用特定的centersize來初始化。在下麵Rect結構體定義中,我們為著三種方式提供了三個自定義的構造器:

struct Rect {
    var origin = Point()
    var size = Size()
    init() {}
    init(origin: Point, size: Size) {
        self.origin = origin
        self.size = size
    }
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}

第一個Rect構造器init(),在功能上跟冇有自定義構造器時自動獲得的默認構造器是一樣的。這個構造器是一個空函數,使用一對大括號{}來描述,它冇有執行任何定製的構造過程。調用這個構造器將返回一個Rect實例,它的originsize屬性都使用定義時的默認值Point(x: 0.0, y: 0.0)Size(width: 0.0, height: 0.0)

let basicRect = Rect()
// basicRect 的原點是 (0.0, 0.0),尺寸是 (0.0, 0.0)

第二個Rect構造器init(origin:size:),在功能上跟結構體在冇有自定義構造器時獲得的逐一成員構造器是一樣的。這個構造器隻是簡單的將originsize的參數值賦給對應的存儲型屬性:

let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
    size: Size(width: 5.0, height: 5.0))
// originRect 的原點是 (2.0, 2.0),尺寸是 (5.0, 5.0)

第三個Rect構造器init(center:size:)稍微複雜一點。它先通過centersize的值計算出origin的坐標。然後再調用(或代理給)init(origin:size:)構造器來將新的originsize值賦值到對應的屬性中:

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),

size: Size(width: 3.0, height: 3.0))

// centerRect 的原點是 (2.5, 2.5),尺寸是 (3.0, 3.0)

構造器init(center:size:)可以自己將originsize的新值賦值到對應的屬性中。然而儘量利用現有的構造器和它所提供的功能來實現init(center:size:)的功能,是更方便、更清晰和更直觀的方法。


注意:
如果你想用另外一種不需要自己定義init()init(origin:size:)的方式來實現這個例子,請參考擴展