5月27日 11:28

Swift 访问控制有哪些级别?open 和 public 有什么区别?

Swift 有五个访问级别,从宽松到严格:open > public > internal > fileprivate > private。internal 是默认值——不写访问修饰符就是 internal。

核心区别在于两个维度:谁能访问(同模块/跨模块/同文件/同作用域),和能不能继承重写(只有 open 允许跨模块继承和重写)。

级别同模块跨模块可继承重写
open✅(跨模块)
public❌(跨模块不可重写)
internal✅(同模块内)
fileprivate同文件同文件内
private同作用域同作用域内

open 和 public 的唯一区别:open 允许跨模块继承和重写,public 不允许。框架对外暴露的基类用 open,工具类/辅助类用 public。

追问

open 和 public 有什么区别?什么时候用 open?

open 允许其他模块继承类和重写方法,public 只允许访问不允许继承重写。用 open 的场景:你设计一个框架,希望使用者能继承你的基类来定制行为——UIKit 的 UIViewController 就是 open 的。用 public 的场景:功能完整的类,不希望被子类化——比如工具类、配置类。

fileprivate 和 private 有什么区别?

private 限制在定义的作用域内——类里的 private 属性,类的方法能访问,但扩展(同文件)不能访问(Swift 4 之前)。fileprivate 限制在定义的文件内——同文件的所有类型和扩展都能访问。Swift 4 之后 private 在同文件的扩展里也能访问了,所以 fileprivate 的用武之地变少了。如果多个类型需要共享某个属性或方法,放在同文件里用 fileprivate。

默认访问级别是什么?为什么不写修饰符就是 internal?

Swift 的哲学是"模块即边界"——大部分代码只在模块内部使用,不需要暴露给外部。internal 正好对应这个边界:模块内可见,模块外不可见。不写修饰符就是 internal,减少了大量样板代码。只有明确需要跨模块的 API 才需要写 public 或 open。

子类的访问级别可以比父类更严格吗?

可以。子类可以把父类的 open 方法重写为 public,但不能反过来——父类是 public 的方法,子类不能重写为 open。规则是"子类的访问级别不能比父类更宽松",但重写时可以收紧。属性也一样——父类 public var,子类可以重写为 internal var。

访问控制和泛型有什么交互?

泛型类型的访问级别取决于类型本身和泛型参数中最严格的那个。public class Container<T: PrivateProtocol> 编译不过——public 类型不能依赖 private 协议。函数同理:public func process(_ item: InternalType) 也编译不过。规则是"实体的访问级别不能比它依赖的类型更高"。

写段代码

swift
// 框架对外 API open class BaseService { open func execute() { } // 允许跨模块重写 public func validate() { } // 允许跨模块调用,但不允许重写 } // 模块内部实现 class InternalHelper { // 默认 internal fileprivate func assist() { } // 同文件可访问 private var state: Int = 0 // 同作用域可访问 } // 子类收紧访问级别 class MyService: BaseService { public override func execute() { } // ✅ 收紧:open → public }
标签:Swift