在 Swift 中限制类型的扩展名?

Restrict extensions on a type in Swift?

我在 Swift 中有一个特定的 class,我想限制创建扩展。我尝试添加 final 关键字,但它不限制扩展名:

final class MyTest {
    func testFunc() {}
}

extension MyTest {
    func testFunc2() {}
}

let test = MyTest()
test.testFunc2()

这可能吗?

您无法阻止他人向您的 class 添加扩展。就像您无法阻止其他开发人员编写使用您的 class.

的函数一样

The final modifier only prevents subclassing. Other developers will always be able to add extensions.

真的有问题吗?

恕我直言,它不是。

我们来看看这个class

final class Person {
    private let name: String
    func tellName() -> String { return "I am \(name)" }
    init(name: String) {
        self.name = name
    }
}

现在另一个开发人员可以编写(到另一个源文件中)这个函数

func presentAndTellName(person: Person) {
    print("Hello everybody! \(person.tellName())")
}

这在其他几种不支持扩展的编程语言中是可能的。好吧,这基本上是有多少种编程语言可以工作,这也是我们拥有访问控制的原因之一(私有,public,...)。

另一个开发者实际上不能使用我们的 class 的 private properties/methods(除非它可以访问我们的源文件)。他也不能向 Person 添加属性,因为它是一个标记为 final 的 class,所以 subclassing 是禁止的。他只能编写使用它的代码。

我们都可以接受吗?

然而,编写一个接受参数并仅处理该参数的函数有时很丑陋。函数应该是方法,参数值应该是实例。

所以我们使用扩展来转换这个

func presentAndTellName(person: Person) {
    print("Hello everybody! \(person.tellName())")
}

进入这个

extension Person {
    func presentAndTellName() {
        print("Hello everybody! \(self.tellName())")
    }
}

这只是一种编写相同逻辑并使其在 OOP 语法糖中可用的方法。

现在不用写这个

presentAndTellName(person)

我们可以这样写

person.presentAndTellName()

将您的资料设为私有

那么如何保护您的一些 class (/struct) 逻辑和数据不受扩展的影响?使用您用来保护这些东西免受源文件外部函数影响的相同机制,只需将它们标记为 private。这样其他开发人员将无法将它们用于他们的扩展。

让我们再看看我们的人物 class。

class Person {
    private let name: String
    func tellName() -> String { return "I am \(name)" }
    init(name: String) {
        self.name = name
    }
}

name 属性 是私有市场,因此 没有办法 并且外部函数或扩展程序将能够直接访问它。

等等,协议呢?

好的,这可能是扩展提供的不仅仅是更好语法的唯一东西。

事实上给定这个协议

protocol Runner {
    func run()
}

我们可以符合它 class 我们不拥有

extension Person: Runner {
    func run() { print("") }
}