Swift学习笔记20-访问控制

张开发
2026/4/7 8:33:44 15 分钟阅读

分享文章

Swift学习笔记20-访问控制
// // main.swift // class 20 // // Created by sakiko on 2026/4/6. // import Foundation print(Hello, World!) //访问控制(Access Control)访问控制经过严格的分类来定义哪些部分可以被访问和修改。 //注“实体”通常是指程序中可以定义和操作的基本构件或对象类、结构体、协议、枚举、函数、变量等。 //open允许在定义实体的模块、其他模块中访问,即可以被其他模块继承和重写)。(open只能用在类、类成员上) //使用范围最宽适用于库和框架的公开接口。 //public:允许在定义实体的模块、其他模块中访问不允许其他模块继承、重写。可以在任何地方访问。 //适用于需要共享但不会被修改的代码部分。 //internal:只允许在定义实体的模块中访问不允许在其他模块中访问。可以在同一模块内访问默认。 //绝大部分实体默认都是internal级别适合在模块内部使用隐藏实现细节。 //fileprivate:只允许在定义实体的源文件中访问。只能在同一个文件中访问。 //适用于希望限制访问到单一文件但又共享给该文件内多个实体的情况。 //private只允许在定义实体的封闭声明中访问只允许在定义该实体的闭包或类中访问封闭性最强。只能在同一个类或结构体内部访问。 //适用于更严格的限制隐藏实现细节避免外部访问。 //访问级别的使用准则一个实体不可以被更低访问级别的实体定义 /* 变量和常量类型 变量、常量类型 ≥ 变量、常量 变量或常量的访问级别不能低于其存储类型的访问级别。例如如果一个变量是 public那么它的类型也必须是 public 或更高。 参数类型和返回值类型 参数类型、返回值类型 ≥ 函数 函数的参数和返回值的访问级别不能低于该函数的访问级别。这意味着如果一个函数是 internal 的那么它的参数和返回值也应至少是 internal。 父类和子类 父类 ≥ 子类 子类的访问级别不能高于其父类。这是为了确保继承关系中的安全性和一致性。 父协议和子协议 父协议 ≥ 子协议 子协议的访问级别不能高于它所遵循的父协议。这确保了协议的可预测性和向后兼容性。 原始类型和类型别名 原始类型 ≥ typealias 定义的类型的访问级别应高于它所关联的类型别名。这意味着如果一个类型是 public那么它的别名也应至少是 public。 初始值类型、关联值类型 ≥ 枚举类型 枚举中的初始值和关联值类型的访问级别应不低于枚举本身。这一条强调了枚举的安全性和结构完整性。 定义类型 A 时的其他类型 定义类型 A 时用到的其他类型 ≥ 类类型 A 这意味着用于定义某个类型 A 的其他类型的访问级别不能高于 A 本身。 */ //元组类型的访问级别是所有成员类型中最低的那个。 //元组的访问级别取决于其所有组成类型的最低访问级别。元组的访问级别会受到其内部各个元素类型的限制必须与内部元素中最低的访问级别一致。 //泛型的访问级别是【类型的访问级别】以及【所有泛型类型参数的访问级别】中最低的那个 internal class Car {} fileprivate class Dog {} public class PersonT1, T2{} fileprivate var p PersonCar, Dog() //泛型类 PersonT1, T2 的访问级别取决于所有类型参数的访问级别以及类本身的访问级别中最严格最低的那一个。 //所以PersonCar, Dog的访问级别是fileprivate(最严格的) //成员、嵌套类型 //类型的访问级别会影响成员属性、方法、初始化器、下标以及嵌套类型的默认访问级别。 //一般情况下类型为private或fileprivate那么成员/嵌套类型也默认是private或fileprivate //一般情况下类型为internal或public那么成员/嵌套类型默认是internal public class PublicClass { public var p1 0//public var p2 0//internal fileprivate func f1(){}//只允许在定义实体的源文件中访问。 private func f2() {}//只允许在定义实体的封闭声明中访问只允许在定义该实体的闭包或类中访问封闭性最强。 } class InternalClass { //internal var p 0//internal fileprivate func f1(){}//fileprivate private func f2(){}//private } fileprivate class FilePrivateClass {//fileprivate func f1() {}//fileprivate(默认是fileprivate private func f2(){}//private } private class PrivateClass {//private func f() {} } //成员的重写 //子类重写成员的访问级别必须【大于等于】子类的访问级别或者大于等于父类被重写成员的访问级别。 //父类的成员不能被成员作用域外定义的子类重写。 //注意如果父类的成员是 private子类就不能重写它否则会触发错误。 /* public class Personq { private var age: Int 0 } public class Student : Person { //这里会也错误因为父类是private不允许子类重写它只能在当前类内部访问 override var age: Int { set{} get{} } } */ public class Personq { private var age: Int 0 public class Studentq : Personq { override var age: Int { set{} get{10} } } }//这个是写在里面了所以是可以被private允许访问的。所以这样没问题 private class Person1{} //当在Swift中定义一个类、结构体或其他类型时如果它不是位于其他类或结构体内部它就是在全局作用域下定义的。 private struct Dog1 { var age: Int 0 func run(){} } fileprivate struct Person2 { var dog: Dog1 Dog1() mutating func walk(){ dog.run() dog.age 1 } } // 以上可以运行。 //直接在全局作用域下定义的private等价于fileprivate /* private struct Dog2 { private var age: Int 0 private func run(){} } fileprivate struct Personw { var dog: Dog2 Dog2() //这是没法编译通过的因为dog2是private mutating func walk() { dog.run() dog.age 1 } } */ //getter、setter:默认自动接收他们所属环境的访问级别 //可以给setter单独设置一个比getter更低的访问级别用以限制写的权限其实这里不是很懂算了 fileprivate(set)public var num 10 class Person3 { private(set)var age 0 fileprivate(set) public var weight: Int { set {} get { 10 } } internal( set )public subscript(index: Int) - Int { set {} get { index } } } //初始化器 //一个 public 类的初始化器想要被模块外部调用必须显式提供写出来。 //因为public类的默认初始化器是internal级别的意味着它在同一个模块内可用但不能在其他模块中使用 //required初始化器大于等于他的默认访问级别(internal) //当在 Swift 中为一个类声明一个 required 初始化器时这个初始化器的访问级别必须至少和它的默认访问级别一样高。 //如果结构体有private或fileprivate的存储实例属性那么它的成员初始化器也是private或fileprivate。否则就是internal //枚举类型的case //不能给enum的每个case单独设置访问级别每个case自动接收enum的访问级别 //public enum定义的case也是public //协议协议中定义的要求自动接收协议的访问级别不能单独设置访问级别。 //public协议定义的要求也是public //协议实现的访问级别必须大于等于类型的访问级别或者大于等于协议的访问级别声明了某协议的实体的访问级别必须大于等于协议本身 public protocol Runnable { func run() } public class Persone : Runnable {//等于协议的访问级别所以可以通过 public func run() { } } //扩展 //如果显式设置了扩展的访问级别扩展添加的成员自动接收扩展的访问级别 //如果没有显式设置扩展的访问级别扩展添加的成员访问级别和(原)类型中定义的成员一样。 //可以单独给扩展添加的成员设置访问级别 //不能将扩展extension用于遵循某个协议的类型来显式设置扩展的访问级别。 //人话版如果某个类型已经遵循了一个协议你不能通过扩展来改变这个类型的访问权限。 //如果协议是public那么即使给这个类型写了一个private扩展这个扩展的访问级别也是无效的。 //在同一文件中的扩展可以写成类似多个部分的类型声明。 public class Personr { private func run0() {} //1.0在原本的声明中声明一个私有成员 private func eat0() { run1() //2.2这是原本的声明中可以在此访问 } } extension Personr { private func run1(){} //2.0在扩展中声明一个私有成员 private func eat1(){ run0()//1.1可以在同一文件的扩展中访问它 } } extension Personr { private func eat2(){ run1()//2.1可以在同一文件的扩展中访问它 } } //将方法赋值给var/let //方法也可以像函数那样赋值给一个let或者var struct Person123 { var age: Int func run(_ v: Int) { print(func run, age, v)} //这是实例方法 static func run(_ v:Int) {print(static func run, v)}//这是静态方法 //static表示静态方法属于类而不是类的实例。可以在不创建类的实例的情况下直接调用静态方法。 } let fn1 Person123.run fn1(10) //static func run 10 调用的是静态方法整个方法而非实例 let fn2:(Int) - () Person123.run fn2(20)//static func run 20 调用的是静态方法整个方法而非实例 let fn3:(Person123) - ((Int) - ()) Person123.run fn3(Person123(age:18))(30)//func run 18 30 //当调用 fn3(Person(age: 18))(30) 时首先创建了一个 Person 的实例且 age 为 18。 //然后fn3 被调用返回一个接受 Int 参数的函数这个函数是实例方法 run 的实现。此时run 可以访问 age 的值。 //因此当传入 30 时会打印出“func run 18 30”。

更多文章