十八、访问控制

本文详细介绍了Swift中的访问控制机制,包括open、public、internal、fileprivate和private五个访问级别,以及它们在类、枚举、结构体、协议、泛型、成员和初始化器等场景的应用。此外,还讨论了成员重写、元组类型、泛型类型的访问规则,以及如何通过访问级别控制协议实现和扩展。同时,文章强调了访问级别在不同类型成员和嵌套类型中的默认设定和特殊情况。
摘要由CSDN通过智能技术生成

/*
 1.访问控制
 在访问权限控制这一块,swift提供了5个不同的访问级别,以下是从高到低排列,实体指被访问级别修饰的内容
 open:允许在定义实体的模块、其他模块中访问,允许其他模块进行继承、重写(open只能用在类、类成员上)
 public:允许在定义实体的模块、其他模块中访问,不允许其他模块进行继承、重写
 internal:只允许在定义实体的模块中访问,不允许在其他模块中访问
 fileprivate:只允许在定义实体的源文件中访问
 private:只允许在定义实体的封闭声明中访问
 绝大多数实体默认都是internal级别
 2.访问级别的使用准则
 一个实体不可以被更低访问级别的实体定义,核心准则,比如
 常量\常量类型>=变量\常量
 参数类型、返回值类型>=函数
 父类>=子类
 父协议>=子协议
 原类型>=typealias
 原始值类型、关联值类型>=枚举类型
 定义类型A时用到的其他类型>=类型A
 
 也就是左边去定义右边,左边类型>=右边
 */
//变量类型的访问级别public >= 变量的访问级别internal
public class PP {}
internal var pp: PP

fileprivate typealias MyInt = Int
fileprivate typealias MyString = String
fileprivate enum Score { //fileprivate 而不是 public
    case point(MyInt)
    case grade(MyString)
}

//3.元组类型
//元组类型的访问级别是所有成员类型最低的那个
internal struct Dog {}
fileprivate class Person {}
//(Dog, Person)的访问级别是fileprivate
fileprivate var data1: (Dog, Person)
private var data2: (Dog, Person)

//4.泛型类型
//泛型类型的访问级别是类型的访问级别以及所有泛型类型参数的访问级别中最低的那个
internal class Car {}
fileprivate class Bus {}
public class Son<T1, T2> {}
//Person<Car, Bus>的访问级别是fileprivate
fileprivate var p = Son<Car, Bus>()

//5.成员、嵌套类型
//类型的访问级别会影响成员(属性、方法、初始化器、下标)、嵌套类型的默认访问级别
//一般情况下,类型为private或fileprivate,那么成员、嵌套类型默认也是private、fileprivate
fileprivate class Lion {
    var age = 0 //fileprivate
    func run() {} //fileprivate
    enum Season { case spring, summer } //fileprivate
}
//一般情况下,类型为internal或public,那么成员、嵌套类型默认是internal
public class Mouse {
    var age = 0 //internal
    func run() {} //internal
    enum Season { case spring, summer } //internal
}

//成员的重写
//子类重写的成员的访问级别必须>=子类分访问级别,或者>=父类被重写成员的访问级别
//下边的协议也一样
class Big {
    internal func run() {}
}
fileprivate class small : Big {
    fileprivate override func run() {} //fileprivate >= internal、fileprivate中的最小一个
}
//父类的成员不能被成员作用域外定义的子类重写
class AA {
    private var age: Int = 0
    private func run() {}
    //下边代码写到这里可编译通过,写在AA大括号外编译不通过
    class aa : AA {
        override var age: Int {
            set {}
            get {10}
        }
        override func run() {}
    }
}

//6.下面代码能都编译通过?分情况
class Test {
//    private class sun {}
//    fileprivate class moon : sun {} //编译不通过
}

private class sun {}
fileprivate class moon : sun {} //可以编译通过,在全局作用域下定义的private等价于fileprivate

class test1 {
    private struct Dog {
        private var age: Int = 0 //写了 private值只能在结构体大括号内访问
        func run() {} //没写 private 就跟Dog一样可以在test1大括号内访问
    }
    private struct Person {
        var dog: Dog = Dog()
        mutating func walk() {
//            dog.age = 1 //报错
            dog.run()
        }
        
    }
}

//7.getter、setter
//getter、setter默认自动接收它们所属环境的访问级别
//可以给setter单独设置一个比getter更低的访问级别,用以限制写的权限
fileprivate(set) public var num = 10
class Stone {
    private(set) var age = 0
    fileprivate(set) public var weight: Int {
        set {}
        get { 10 }
    }
    internal(set) public subscript(index: Int) -> Int {
        set {}
        get { index }
    }
}

//8.初始化器
//如果一个public类想再另一个模块调用编译生成的默认无参初始化器,必须显示提供public的无参初始化器,因为public类的默认初始化器是internal级别
//abc.dylib
public class A {
    public init() {} //删掉public 无法访问A()
}
//TestSwift
var a = A()
//required初始化器>=它的默认访问级别
public class BB {
    internal required init () {} //internal >= internal
}

//如果结构体有private、fileprivate的存储实例属性,那么它的成员初始化器也是private、fileprivate,否则默认就是internal
struct Point {
    private var x = 0 //只许在大括号里访问
    var y = 0
}
//var p = Point(x: 10, y: 10) //报错

//9.枚举类型的case:枚举是啥case就是啥
//不能给enum的每个case单独设置访问级别,每个case自动接收enum的访问级别,public enum定义的case也是public
public enum Season {
    case spring
    case summer, autumn, winter
}

//10.协议
//协议中定义的要求自动接收协议的访问级别,不能单独设置访问级别,public定义的要求也是public
internal protocol Runn {
    func run() //也internal
}
//协议实现的访问级别必须>=类型的访问级别,或者>=协议的访问级别
fileprivate protocol Walkable {
    func walk()
}
public class Duck : Walkable {
    fileprivate func walk() {} //fileprivate >= public、fileprivate中的最小一个
}
//下面代码编译通过么?不通过
public protocol Jumpabble {
    func jump()
}
//public class Frog : Jumpabble {
//    func jump() {} //因为默认是internal 加上public就不报错
//}

//11.拓展
class Person1 {}
fileprivate extension Person1 {
    func run() {} //如果有显示设置拓展的访问级别,拓展添加的成员自动接收拓展的访问级别即这里是fileprivate
}

class Person2 { func run() {} }
extension Person2 {
//    func run() {} //如果没有显示设置拓展的访问级别,拓展添加的成员的默认访问级别跟直接在类型中定义的成员一样
}

class Person3 {  }
extension Person3 {
    private func run() {} //可以单独给拓展添加的成员设置访问级别
}

class Person4 {}
extension Person4 : Runn {//不能给用于遵守协议的拓展显示设置拓展的访问级别即这里不能添加fileprivate等访问级别
    func run() {}
}

/*
 在同一文件中的拓展,可以写成类似多个部分的类型声明,在原本的声明中声明一个私有成员,可以再同一文件的拓展中访问它,在拓展中国声明的一个私有成员,可以在同一文件的其他拓展中、原本声明中访问它。总之可以理解为他们是在同一个类文件下的不同部分所以可以不收private限制访问。
 */
public class Cup {
    private func run0() {}
    private func eat0() {
        run1()
    }
}
extension Cup {
    private func run1() {}
    private func eat1() {
        run0()
    }
}
extension Cup {
    private func eat2() {
        run1()
    }
}

//12.将方法赋值给var/let
struct Rabbit {
    var age: Int
    func run(_ v: Int){ print("func run",age,v) }
    static func run(_ v: Int){
        print("static func run",v)
    }
}

let fn1 = Rabbit.run
fn1(10) //static func run 10
let fn2: (Int) -> () = Rabbit.run
fn2(20) //static func run 10
let fn3: (Rabbit) -> ((Int) -> ()) = Rabbit.run
fn3(Rabbit(age: 18))(30) //func run 18 30

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值