Swift struct default 初始化器和 memberwise 初始化器

39 阅读2分钟

一个 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 已实现。