为什么 Swift 中的公共类/结构需要显式公共初始值设定项?

2024-02-03

考虑模块中的以下类(也同样适用于结构体):

public class Foo {
   public func bar() {
       // method body
   }
}

注意,它没有显式的初始化器;这个例子不需要任何特殊的初始化。该类将暴露给其他模块,因为它被标记为public。然而,当模块外部的代码尝试初始化它时,编译器会抱怨:

let foo = Foo() // 'Foo' initializer is inaccessible due to 'internal' protection level

为了满足编译器的要求,我必须定义一个显式的空初始化器标记public:

public class Foo {
   public init() {
       // This initializer intentionally left empty
   }

   public func bar() {
       // do something useful
   }
}

为什么,如果类是明确的public,我需要显式定义一个公共初始值设定项吗?它不应该隐式地有一个公共初始值设定项吗?

有一个相关问题here https://stackoverflow.com/questions/27635489/why-do-i-need-to-write-initializer-for-struct-in-swift-in-order-to-use-it-in-uni,与单元测试有关,但我发现它并没有真正触及我认为令人惊讶的问题的设计理念的核心。


将类标记为公共并不一定意味着开发人员希望该类被公开初始化。例如,我经常编写基类,这些基类的存在只是为了我能够对它们进行子类化。我给这些超类internal初始化器,以便它们的子类可以访问它们,但外部世界的子类不应该直接使用它们。例如,Operation in Foundation没有可访问的初始值设定项,但该类是公共的。它只是为了被子类化。这在 Objective-C 中被认为是一个抽象类。

由于 Swift 不包含对抽象类的显式支持,因此将类设为公共但没有公共初始化器的行为基本上充当抽象类(除了每个函数仍然必须有一个默认定义,无论是在类本身还是在某些协议扩展中) 。

考虑到这一点,以下是一些 Swift 规则:

  • 如果你的班级被标记private,所有变量、初始化和函数都将默认为private.
  • 如果你的班级被标记internal(默认),public, or open,所有变量、初始化和函数都将默认为internal.
  • 子类的超类必须至少具有同样的可访问性。
  • 声明的类和类成员publicObjective-C 中的内容导入到 Swift 中为open,因为 Objective-C 中没有这样的区别。

第二个就是你遇到的那个。默认 init 采用默认值internal因为 Swift 最不想做的就是将你的 init 公开为公共 API,除非明确指示这样做。

注意:在我的测试中(至少在操场上),似乎随着引入fileprivate:

  • 如果声明了一个类private or fileprivate,似乎班级成员默认为fileprivate除非明确注释private.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Swift 中的公共类/结构需要显式公共初始值设定项? 的相关文章

随机推荐