Swift中的open关键字隐藏了什么?初学者解析
你是否曾在Swift中编写过一个类,给它添加了public,然后试图在另一个模块中继承它——却遇到了编译错误?如果是这样,你并不孤单。这个问题是Stack Overflow上Swift初学者开发者中最常见的问题之一。成千上万的人都在同一个问题上栽了跟头:open关键字。
在本文中,我们将一劳永逸地弄清楚Swift中的open是什么,它与public有何不同,何时应该使用它,以及何时绝对不能使用它。我们将编写实际代码,查看错误并学习如何修复它们。开始吧!
Swift中的访问修饰符系统:简要入门
在深入探讨open之前,让我们回顾一下Swift中有哪些访问级别。共有五个(从最封闭到最开放):
private— 仅在同一文件和同一声明内可访问(例如,在类内部)。fileprivate— 在整个文件范围内可访问。internal— 在整个模块内可访问(这是默认级别)。public— 可从其他模块访问,但不能继承和重写。open— 可从其他模块访问,可以继承和重写。
主要的悬念在于public和open之间的区别。乍一看它们很相似:两者都允许从另一个模块访问类、方法或属性。但有一个根本性的区别,我们现在将通过示例来解析。
示例:一个无法扩展的public类
假设你正在编写一个用于网络操作的库(框架)。你创建了一个NetworkService类并将其设为public:
// 模块:MyNetworkingFrameworkpublic class NetworkService { public func fetchData() { print("从网络获取数据...") }}现在,另一位开发者连接了你的框架,并希望基于它创建自己改进的类:
// 模块:MyAppimport MyNetworkingFramework
// 错误!无法从public类继承class MyNetworkService: NetworkService { override func fetchData() { print("我的自定义获取...") }}编译器将报错。为什么?因为public是从另一个模块只读的访问权限。你可以使用类的实例,调用它的方法,但不能继承它。这是有意为之:库的作者希望控制哪些类可以扩展,哪些不可以。
解决方案:使用open
如果库的作者希望允许继承,他必须明确指定open:
// 模块:MyNetworkingFrameworkopen class NetworkService { open func fetchData() { print("从网络获取数据...") }}现在,在另一个模块中可以安全地继承和重写方法:
// 模块:MyAppimport MyNetworkingFramework
class MyNetworkService: NetworkService { override func fetchData() { print("我的自定义获取,带有额外日志记录...") super.fetchData() }}这就是全部魔法。open关键字是在模块外部进行继承和重写的许可。
为什么open对架构很重要?
Swift和Apple的开发者引入这种区别并非无缘无故。它有助于设计稳定且安全的API。想象一下,你发布了一个库,其中所有的类都是open。