一个 struct 如果没有定义任何自定义初始化器,编译器会生成 memberwise 初始化器。我们看代码
struct S {
var x: Int
}
结构 S 只有一个存储属性 x,编译器会生成 memberwise 初始化器。
init(x: Int) {
self.x = x
}
如果属性 x 有默认值,
struct S {
var x: Int = 6
}
编译器会生成 default 初始化器 init() 和 memberwise 初始化器 init(x: Int = 6)。
init() {
}
init(x: Int = 6) {
self.x = x
}
生成 default 初始化器 init() 的条件是 struct 为所有属性提供了默认值,并且没有定义任何自定义初始化器。default 初始化器简单地创建一个所有属性值都设置为它们默认值的实例。
结构 S 及其属性 x 的访问级别都是 internal,我们把 x 的访问级别改为 private,
struct S {
private var x: Int
}
此时
var s = S(x: 12)
会报错,'S' initializer is inaccessible due to 'private' protection level,因为生成的 memberwise 初始化器 init(x: Int) 访问 private 属性 x,它也为 private,只能在 struct 内部访问。
struct S {
private var x: Int
static func create(x: Int) -> S {
let s = S(x: x)
return s
}
}
var s = S.create(x: 12)
静态方法 create(x: Int) 能访问 private memberwise 初始化器,上面代码能正常编译。
再看属性 x 有默认值的情况,
struct S {
private var x: Int = 6
}
编译器会生成 default 初始化器 init() 和 private memberwise 初始化器 init(x: Int = 6)。
init() {
}
private init(x: Int = 6) {
self.x = x
}
由于 default 初始化器 init() 未访问属性 x,它访问级别仍然是 internal。因此,
var s = S()
能编译通过。
var s = S(x: 12)
报错,Argument passed to call that takes no arguments。
然而
struct S {
private var x: Int = 6
static func create(x: Int) -> S {
let s = S(x: x)
return s
}
}
能编译通过。
以上4种情况总结如下:
以上都只有一个属性,如果 struct 有多个属性,上述规则仍然成立。
struct S {
private var x: Int = 6
var y: Int
}
编译器生成 memberwise 初始化器,
private init(x: Int = 6, y: Int) {
self.x = x
self.y = y
}
只要有一个属性是 private,则 memberwise 初始化器就是 private。
var s = S(y: 6)
报错,'S' initializer is inaccessible due to 'private' protection level。
如果 y 有默认值,
struct S {
private var x: Int = 6
var y: Int = 8
}
相信大家已经猜到了,生成 default 初始化器 init() 和 memberwise 初始化器 init(x: Int = 6, y: Int = 8)。
init() {
}
private init(x: Int = 6, y: Int = 8) {
self.x = x
self.y = y
}
init() 访问级别是 internal,init(x: Int = 6, y: Int = 8) 访问级别是 private。
var s = S()
能编译通过。
struct S {
private var x: Int = 6
var y: Int = 8
static func create(x: Int, y: Int) -> S {
let s = S(x: 12, y: 12)
return s
}
}
能编译通过。
以上代码在 Xcode 26.3 验证。不过,在不久的将来,memberwise 初始化器的规则会改变,
var s = S(y: 6)
不会报错,因为提案 SE-0502 已实现。