Swift 如何使结构体的默认初始化器为私有?

4
我们在代码中有一个名为 "single " 的结构体,如下所示:
struct Foo {
    let bar: String
    static let sharedInstance = Foo(bar: "blah")
}

除了调用者仍然可以使用以下方法初始化另一个Foo实例外,它的工作很好:
let foo = Foo.init(bar: "blah")

有没有办法使生成的初始化器变为私有?


我们尝试了像这样明确定义初始化器:

struct Foo {
    let bar: String
    static let sharedInstance = Foo(bar: "blah")

    private init(bar: String) {
        self.bar = bar
    }
}

代码可行,但每次添加/更改属性时都必须修改初始化器,有点烦人。我喜欢初始化器自动生成的方式,不必写这些样板代码。这种方式可行吗?


另一种选择是仅定义没有参数的 private init(),并为所有属性赋初始值:let bar = "blah" ... - Martin R
你好@MartinR,使用结构体实现单例模式是否有效? - Ahmad F
2
@AhmadF:确实如此。来自https://dev59.com/ZVoV5IYBdhLWcg3wCrAn#36788519的内容是:“主要区别在于基于类的可变单例可以工作,而基于结构的可变“单例”则不行”。 - Martin R
1个回答

1
如果您注意到正在实现以下内容:
struct Foo {
    let bar: String
    static let sharedInstance = Foo(bar: "blah")
}

即使没有为bar赋初始值,也是合法的,为什么?因为Swift结构体有一个默认初始化器,称为成员逐一初始化器:

如果结构体类型没有定义任何自定义初始化器,则自动接收成员逐一初始化器。与默认初始化器不同,即使结构体具有没有默认值的存储属性,它也会接收成员逐一初始化器。

成员逐一初始化器是初始化新结构实例的成员属性的简写方式。可以通过名称将新实例的属性的初始值传递给成员逐一初始化器。

这意味着,如果您尝试创建Foo结构体的新实例,编译器应该 - 自动 - 提供:

enter image description here

然而,你可以通过实现 private init() 来摆脱它,但你必须确保所有存储的属性都有“虚拟”初始值(或者让它们成为可选值...),因为结构体不再具有初始化程序来保证存储的属性具有值。这应该类似于:
struct Foo {
    var bar: String = ""
    static var shared = Foo()

    private init() {}
}

备注: 当实现单例模式时,建议使用 class,您可能想要查看此答案(感谢MartinR提出的建议)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接