构造器 2个月前

编程语言
378
构造器

默认构造器

如果结构体或类为所有属性提供了默认值,又没有提供任何自定义的构造器,那么 Swift 会给这些结构体或类提供一个 默认构造器 。这个默认构造器将简单地创建一个所有属性值都设置为它们默认值的实例。

下面例子中定义了一个类 ShoppingListItem,它封装了购物清单中的某一物品的名字(name)、数量(quantity)和购买状态 purchase state

classShoppingListItem {
var name: String?
var quantity =1
var purchased =false
}
var item =ShoppingListItem()

由于 ShoppingListItem 类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个将为所有属性设置默认值的并创建实例的默认构造器(由于 name 属性是可选 String 类型,它将接收一个默认 nil 的默认值,尽管代码中没有写出这个值)。上面例子中使用默认构造器创造了一个 ShoppingListItem 类的实例(使用 ShoppingListItem() 形式的构造器语法),并将其赋值给变量 item

结构体的逐一成员构造器

结构体如果没有定义任何自定义构造器,它们将自动获得一个 逐一成员构造器(memberwise initializer) 。不像默认构造器,即使存储型属性没有默认值,结构体也会获得逐一成员构造器。

逐一成员构造器是用来初始化结构体新实例里成员属性的快捷方法。新实例的属性初始值可以通过名字传入逐一成员构造器中。

下面例子中定义了一个结构体 Size,它包含两个属性 widthheight。根据这两个属性默认赋值为 0.0 ,它们的类型被推断出来为 Double

结构体 Size 自动获得了一个逐一成员构造器 init(width:height:)。你可以用它来创建新的 Size 实例:

structSize {
var width =0.0, height =0.0
}
let twoByTwo =Size(width:2.0, height:2.0)

当你调用一个逐一成员构造器(memberwise initializer)时,可以省略任何一个有默认值的属性。在上面这个例子中,Size 结构体的 heightwidth 属性各有一个默认值。你可以省略两者或两者之一,对于被省略的属性,构造器会使用默认值。举个例子:

let zeroByTwo = Size(height: 2.0)
print(zeroByTwo.width, zeroByTwo.height)
// 打印 "0.0 2.0"

let zeroByZero = Size()
print(zeroByZero.width, zeroByZero.height)
// 打印 "0.0 0.0"

值类型的构造器代理

构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为 构造器代理 ,它能避免多个构造器间的代码重复。

构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给自己的其它构造器。类则不同,它可以继承自其它类(请参考 继承)。这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。这些责任将在后续章节 类的继承和构造过程 中介绍。

对于值类型,你可以使用 self.init 在自定义的构造器中引用相同类型中的其它构造器。并且你只能在构造器内部调用 self.init

请注意,如果你为某个值类型定义了一个自定义的构造器,你将无法访问到默认构造器(如果是结构体,还将无法访问逐一成员构造器)。这种限制避免了在一个更复杂的构造器中做了额外的重要设置,但有人不小心使用自动生成的构造器而导致错误的情况。

注意

假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(extension)中,而不是写在值类型的原始定义中。想查看更多内容,请查看 扩展 章节。

下面例子定义一个自定义结构体 Rect,用来代表几何矩形。这个例子需要两个辅助的结构体 SizePoint,它们各自为其所有的属性提供了默认初始值 0.0

structSize {
var width =0.0, height =0.0
}

structPoint {
var x =0.0, y =0.0
}

你可以通过以下三种方式为 Rect 创建实例——使用含有默认值的 originsize 属性来初始化;提供指定的 originsize 实例来初始化;提供指定的 centersize 来初始化。在下面 Rect 结构体定义中,我们为这三种方式提供了三个自定义的构造器:

structRect {
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 的 origin 是 (0.0, 0.0),size 是 (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 的 origin 是 (2.0, 2.0),size 是 (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 的 origin 是 (2.5, 2.5),size 是 (3.0, 3.0)

构造器 init(center:size:) 可以直接将 originsize 的新值赋值到对应的属性中。然而,构造器 init(center:size:) 通过使用提供了相关功能的现有构造器将会更加便捷(而且意图更清晰)。

注意

如果你想用另外一种不需要自己定义 init()init(origin:size:) 的方式来实现这个例子,请参考 扩展

image
EchoEcho官方
无论前方如何,请不要后悔与我相遇。
1377
发布数
439
关注者
2223610
累计阅读

热门教程文档

Spring Boot
24小节
Kotlin
68小节
Javascript
24小节
Vue
25小节
Djiango
17小节