在Swift中,定义为struct的类型会自动获得编译器合成的默认初始化器——所谓的“memberwise初始化器”,因为编译器会根据给定的struct成员(即其存储的属性)生成它。

例如,如果我们定义了一个用户结构,它有一个name和一个preferences属性,我们可以通过传递这两个属性的值来使用它的memberwise初始化来创建实例:

struct User {
    var name: String
    var preferences: Preferences
}

let user = User(name: "John", preferences: Preferences())

另一方面,当编译器合成memberwise初始化式时,计算属性完全被忽略 - 所以即使添加了一个,仍然可以像前面一样继续使用上面的初始化式:

struct User {
    var name: String
    var preferences: Preferences
    var icon: Icon { .user }
}

let user = User(name: "John", preferences: Preferences())

在Swift 5.1中,memberwise初始化器也将默认属性值考虑在内 - 这意味着如果我们给preferences属性一个默认值,我们就可以通过传递一个名字来创建一个User实例:

struct User {
    var name: String
    var preferences = Preferences()
}

let user = User(name: "John")

一个很酷的事情是,我们可以继续使用类型的memberwise初始化器,即使该类型有私有属性——只要这些属性有默认值,就像这样:

struct User {
    var name: String
    private var preferences = Preferences()
}

let user = User(name: "John")

然而,如果私有属性没有默认值,我们将不得不手动编写该类型的初始化式——以便能够从外部为该属性注入值:

struct User {
    var name: String
    private var preferences: Preferences

    init(name: String, preferences: Preferences = .init()) {
        self.name = name
        self.preferences = preferences
    }
}

但是要记住的一点是,memberwise初始化式永远不会拥有高于internal的访问级别,这意味着我们只能在定义其类型的模块内部使用它们。

这乍一看似乎是一个奇怪的限制,但它确实有优点,因为我们应该始终为公共消费设计显式的api——而不是将它们与数据的内部结构绑定。

因此,总结一下,我们可以在以下情况下使用结构体的memberwise初始化式:

它的所有成员要么是可见的,要么有一个默认值。
我们正在定义结构体的模块中创建实例。
所有其他情况都要求我们手动实现初始化器,至少目前是这样。

原文链接