一个 struct 如果没有定义任何初始化器,编译器会生成 memberwise 初始化器,而且如果为所有存储属性提供了默认值,同时也会生成 default 初始化器。default 初始化器简单地创建一个所有属性值都设置为它们默认值的实例。
default 初始化器的访问级别与它初始化的 struct 相同,除非该 struct 为 public。 如果 struct 为 public,default 初始化器的访问级别是 internal。
memberwise 初始化器的访问级别与 struct 的存储属性的访问级别有关。如果 struct 的任何一个属性是 private,则 memberwise 初始化器的访问级别是 private。如果任何一个属性是 fileprivate,则访问级别是 fileprivate。否则访问级别是 internal。
我们来看例子,
struct S {
var x: Int
}
结构 S 只有一个存储属性 x,编译器会生成 memberwise 初始化器。存储属性 x 的访问级别是 internal,因此初始化器的访问级别是 internal。
init(x: Int) {
self.x = x
}
如果属性 x 有默认值,
struct S {
var x: Int = 6
}
编译器会生成 default 初始化器 init() 和 memberwise 初始化器 init(x: Int = 6)。S 的访问级别是 internal,default 初始化器 init() 的访问级别也是 internal。memberwise 初始化器的访问级别也是 internal。
init() {
}
init(x: Int = 6) {
self.x = x
}
我们把 x 的访问级别改为 private,
struct S {
private var x: Int
}
此时,由于存储属性 x 是 private,生成的 memberwise 初始化器的访问级别也是 private。
var s = S(x: 12)
会报错,'S' initializer is inaccessible due to 'private' protection level。memberwise 初始化器只能在 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() 和 memberwise 初始化器 init(x: Int = 6)。default 初始化器的访问级别仍然是 internal,memberwise 初始化器的访问级别为 private。
init() {
}
private init(x: Int = 6) {
self.x = x
}
因此,
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
}
}
能编译通过。
以上都只有一个属性,进一步看 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
}
由于 x 是 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 已实现。