Swift属性
Swift属性将值跟特定的类,结构体,枚举关联。分为存储属性和计算属性,通常用于特定类型的实例。属性也可以直接用于类型本身,称为类型属性。
可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。
存储属性
存储特定类或结构体的实例里的一个常量或变量。
延迟存储属性
延迟存储属性指当第一次被调用的时候才会计算其初始值的属性。在属性声明前用lazy
来标识,必须将延迟存储属性声明成变量,因为属性的值在实例构造完成之前可能无法得到。
一般用于:
- 延迟对象的创建。
- 当属性的值依赖与其他未知类。
计算属性
计算属性不直接存储值,而是提供一个getter
来获取值,可选的setter
来间接设置其他属性或变量的值。
如果计算属性的setter
没有定义表示新值的参数名,则可以使用默认名称newValue
。
只读计算属性
只有getter
没有getter
的计算属性就是只读计算属性。
注意:必须使用var
来定义计算属性,因为它们的值不是固定的。let
关键值只用来声明常量属性,表示初始化后再也无法修改的值。
属性观察器
属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器。可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(存储属性和计算属性)添加属性观察器。
-
willSet
在设置新值之前调用。 -
didSet
在新的值被设置之后立即调用。 -
willSet
和didSet
观察器在属性初始化过程中不会被调用。
全局变量和局部变量
计算属性和属性观察器所描述的模式也可以用于全局变量和局部变量。
类型属性
类型属性是作为类型定义的一部分写在类型最外层{}
内。使用关键字static
来定义值类型的类型属性,关键字class
来为类定义类型属性。
获取和设置类型属性的值
类型属性的访问通过.
运算符来进行,但是类型属性是通过类型本身来获取和设置,而不是通过实例。
Swift方法
Swift方式是与某些特定类型关联的函数。
OC中类是唯一能够定义方法的类型。Swift中,不仅能够选择是否要定义一个类/结构体/枚举,还能在其中定义方法。
实例方法提供如下方法。
- 可以访问和修改实例属性。
- 提供与实例目的相关的功能。
方法的局部参数名称和外部参数名称
Swift函数可以同时有一个局部名称和一个外部名称。Swift方法默认仅给方法的第一个参数名称一个局部参数名称,同时给之后的参数为全局参数名称。
我们也可以强制给第一个参数添加外部名称,把这个局部名称当中外部名称使用。相反,我们也可以使用_
设置第二个及后续的参数不提供外部名称。
self属性
类型的每个实例都有一个隐含的属性叫做self,self完全等同于该实例本身。
在实例方法中修改值类型
Swift语言中结构体和枚举是值类型。一般情况下,值类型的属性不能在他的实例方法中被修改,但是如果我们想在实例方法中更改结构体或枚举里的属性值,我们该可以选择变异(mutating)这个方法,并且他做的任何改变在方法结束时还会保留在原始结构中。
方法还可以给它隐含的self属性赋值一个全新的实例,这个新实例在方法结束后将替换原来的实例。
类型方法
给类型本身调用的方法叫做类型方法。声明结构体和枚举的类型方法,在方法func
前加关键字static
。类可能会用关键字class
来允许子类重写父类的实现方法。类型方法和实例方法一样用.
语法调用。
下标脚本
下标脚本 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。
举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 someArray[index] ,访问字典(Dictionary)实例中的元素可以这样写 someDictionary[key]。
对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。
语法
下标脚本允许你通过实例后边的[]
传入一个或多个索引值来对实例进行访问和赋值。语法类似于实例方法和计算型属性的混合。
定义下标脚本使用subscript
关键字,显式声明入参和返回类型。与实例方法不同的是下标脚本可以什么为读写或只读,这像计算型属性。
subscript(index: Int) -> Int {
get {
// 用于下标脚本值的声明
}
set(newValue) {
// 执行赋值操作
}
}
用法
通常下标脚本是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式。
你可以在你自己特定的类或结构体中自由的实现下标脚本来提供合适的功能。
例如,Swift 的字典(Dictionary)实现了通过下标脚本对其实例中存放的值进行存取操作。在下标脚本中使用和字典索引相同类型的值,并且把一个字典值类型的值赋值给这个下标脚来为字典设值。
下标脚本选项
- 下标脚本允许任意数量的入参索引,并且每个入参类型也没有限制。
- 下标脚本的返回值也可以是任何类型。
- 下标脚本可以使用变量参数和可变参数。
- 下标脚本的重载:一个类或结构体可以根据自身需要提供多个下标脚本,在定义下标脚本时使用入参类型和个数进行区分。
Swift继承
重写
子类可以通过继承来的方法,属性或下标脚本来实现自己定制的功能,即重写,使用override
关键字来实现重写。
子类中使用super
前缀来访问超类的方法,属性或下标脚本。
重写属性时注意事项:
- 如果在重写属性中提供了
setter
,那么也一定要提供getter
。 - 如果不想在重写版本中的
getter
里修改继承来的属性值,可以直接通过super.xxx
来返回继承来的值。
重写属性观察器
可以在属性重写中为一个继承来的属性添加属性观察器。但是不可以为继承来的常量存储型属性或继承来的只读计算属性添加属性观察器。
防止重写
通过final
关键字防止重写。如果在关键字class
前添加final特性,会将整个类标记为final,这样的类是不可被继承的。
Swift构造过程
构造过程是为了使用某个类、结构体或枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务。
Swift 构造函数使用 init()
方法。
与 Objective-C 中的构造器不同,Swift 的构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。
类实例也可以通过定义析构器(deinitializer
)在类实例释放之前执行清理内存的工作。
存储型属性的初始赋值
类和结构体在实例创建时,必须为所有存储属性设置何时的初始值。存储属性在构造器中赋值时,它们的值是被直接设置的,不会触发属性观测器。
赋值流程:
- 创建初始值
- 在属性定义中指定默认属性值
- 初始化实例,并调用
init()
方法。
语法:
init()
{
// 实例化后执行的代码
}
使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型。
构造参数
可以在定义构造器时提供参数:init(fromLength length: Double, fromBreadth breadth: Double) {}
。
内部和外部参数名
跟函数和方法参数相同,构造参数也存在一个在构造器内部使用的参数名字和一个在调用构造器时使用的外部参数名字。
然而,构造器并不像函数和方法那样在括号前有一个可辨别的名字。所以在调用构造器时,主要通过构造器中的参数名和类型来确定需要调用的构造器。
如果你在定义构造器时没有提供参数的外部名字,Swift 会为每个构造器的参数自动生成一个跟内部名字相同的外部名。
可以通过_
来禁用外部参数名。
可选属性类型
当存储属性声明可选时,将自动初始化为nil
构造器中修改常量属性
只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值。对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。
默认构造器
默认构造器将简单的创建一个所有属性值都设置为默认值的实例:
值类型的构造器代理
构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复。
构造器代理规则
值类型:不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给本身提供的其它构造器。 你可以使用self.init在自定义的构造器中引用其它的属于相同值类型的构造器。
类类型:它可以继承自其它类,这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。
累的继承和构造过程
Swift提供两种类型构造器:指定构造器和遍历构造器
指定构造器:
- 类中最主要的构造器
- 初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。
- 每一个类都必须拥有至少一个指定的构造器。
Init(parameters) {
statements
}
便利构造器:
- 类中比较次要的、辅助型的构造器
- 可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。可以定义便利构造器来创建一个特殊用途或指定输入的实例。
- 只在必要的时候为类提供便利构造器。
convenience init(parameters) {
statements
}
构造器的继承和重载
Swift中的子类不会默认继承父类的构造器。
父类构造器仅在确定和安全的情况下被继承。
当重写父类指定构造器时,需要写override
修饰符。
可失败构造器
如果一个类、结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败的构造器。
变量初始化失败的原因可能有:
- 传入无效的参数值。
- 缺少某种所需的外部资源。
- 没有满足特定条件。
你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在init关键字后面加添问号(init?)或叹号(init!)。
枚举类型的可失败构造器
你可以通过构造一个带一个或多个参数的可失败构造器来获取枚举类型中特定的枚举成员。
类的可失败构造器
值类型(如结构体或枚举类型)的可失败构造器,对何时何地触发构造失败这个行为没有任何的限制。
但是,类的可失败构造器只能在所有的类属性被初始化后和所有类之间的构造器之间的代理调用发生完后触发失败行为。
init?(studname: String) {
self.studname = studname
if studname.isEmpty { return nil }
}
覆盖一个可失败构造器
你也可以用子类的可失败构造器覆盖基类的可失败构造器。
你也可以用子类的非可失败构造器覆盖一个基类的可失败构造器。
你可以用一个非可失败构造器覆盖一个可失败构造器,但反过来却行不通。
一个非可失败的构造器永远也不能代理调用一个可失败构造器。
swift析构过程
在类实例被释放之前,析构函数被立即调用。用关键字deinit
来标识析构函数。析构函数只适合类类型。
析构过程原理
Swift自动释放不在需要的实例以释放资源。
Swift通过ARC处理实例的内存管理。
通常实例被释放时不需要手动去清理。但是,当使用自己的资源时,可能需要一些额外的清理。
语法:
在类的定义中,每个类最多只能有一个析构函数。析构函数不带任何参数,在写法上不带括号。
deinit {
// 执行析构过程
}
Swift可选链
可选链(optional chaining)是一种可以请求和滴哦阿勇属性,方法和脚本的过程,用于请求或调用的目标可能为nil。
可选链返回两个值:nil和目标值。
多次请求或调用可以被链接成一个链,如果任意一个节点为nil将导致整个链失效。
可选链可替代强制解析
通过在属性、方法、或下标脚本的可选值后面放一个问号(?),即可定义一个可选链。
可选链?
- ?放置于可选值后,用来滴哦阿勇方法,属性,下标脚本。
- 当值为nil时输出比较友好的错误信息。
感叹号!
- !强制展开方法、属性、下标脚本可选链
- 放置于可选值后,来调用方法,属性,下标脚本,强制展开值。
- 当值为nil时强制展开执行错误。
为可选链定义模型类
你可以使用可选链来多层调用属性,方法,和下标脚本。这让你可以利用他们之间复杂模型来获取更底层的属性,并检查是否可以成功获取此类底层属性。
Swift自动引用计数(ARC)
ARC功能:
- 当每次使用init()方法创建一个类的新的实例的时候,ARC会分配一大块内存用来存储实例的信息。
- 内存中会包含实例的类型信息,以及这个实例所有相关属性的值。
- 当实例不再被使用时,ARC释放实例所占有的内存,并让释放内存能挪作他用。
- 为了确保使用中的实例不会被销毁,ARC会跟踪和计算每一个实例正在被多少属性,常量,和变量引用。
- 实例赋值给属性,常量,或变量,他们都会创建次实例的强引用,只要强引用还在,实例是不允许被销毁的。
解决实例之间的循环强引用
Swift提供两种方法来解决使用类的属性时所遇到的循环强引用问题:
- 弱引用
weak
- 无主引用
unowned
若引用和无主引用允许循环引用中的一个实例引用引用另外一个实例而不是保持强引用。这样实例能够互相引用而不产生循环强引用。
对于生命周期中会变为nil的实例使用弱引用。
相反的,对于初始化赋值后再也不会被赋值为nil的实例,使用无主引用。
闭包引起的循环强引用
循环强引用会发生在当你将一个闭包赋值给类实例的某个属性,并且这个闭包中又使用了实例。这个闭包体中可能访问了实例的某个属性,例如self.someProperty,或者闭包中调用了实例的某个方法,例如self.someMethod。这两种情况都导致了闭包 "捕获" self,从而产生了循环强引用。
弱引用和无主引用
当闭包和捕获的实例总是相互引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。相反,当捕获引用有时可能会是nil时,将闭包内的捕获定义为弱引用。如果捕获的引用绝对不会置为nil,应该用无主引用,而不是弱引用。
Swift类型转换
Swift语音类型转换可以判断实例的类型,也可以用于检测实例类型是否属于其父类或子类的实例。
Swift中类型转换使用is
和as
操作符实现,is
用于检测值的类型,as用于转换类型。
类型转换也可以用来检测一个类是否实现了某个协议。
向下转型
向下转型,用类型转换操作符(as?或as!)
当不确定向下转型可以成功时,使用类型转换条件形式as?
。条件形式的类型转换总是返回一个可选值,并且弱下转是不可能的,可选值将是nil。
当确定转型一定会成功,则可使用强制形式as!
。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。
Any和AnyObject的类型转换
Swift为不确定类型提供了两种特殊类型别名:
- AnyObject可以代表任何class类型的实例
- Any可以表示任何类型,包括方法类型。
!: 只有当你明确的需要它的行为和功能时才使用Any和AnyObject。在代码里使用期望的明确类型总是更好的。
在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。
Swift扩展
扩展就是向一个已有的类,结构体或枚举类型添加新功能。可以添加新功能,但不能重写已有功能。
Swift扩展功能:
- 添加计算型属性和计算型静态属性
- 定义实例方法和类型方法
- 提供新的构造器。扩展可以向已有类型添加新的构造器。这可以让你扩展其它类型,将你自己的定制类型作为构造器参数,或者提供该类型的原始实现中没有包含的额外初始化选项。扩展可以向类中添加新的便利构造器 init(),但是它们不能向类中添加新的指定构造器或析构函数 deinit() 。
- 定义下标
- 定义和使用新的嵌套类型
- 是一个已有类型符合某个协议。
语法:
使用关键字:extension
extension SomeType {
// 加到SomeType的新功能写到这里
}
一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议:
extension SomeType: SomeProtocol, AnotherProctocol {
// 协议实现写到这里
}
可变实例方法
通过扩展添加的实例方法也可以修改该实例本身。
结构体和枚举类型中修改self或其属性的方法必须将该实例方法标注为mutating
,正如来自原始实现的修改方法一样。
Swift协议
协议规定了用来实现某一特定功能所必须的方法和属性。
任何能够满足协议要求的类型被称为遵循这个协议。
类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。
语法:
protocol SomeProtocol {
// 协议内容
}
要使类遵循某个协议,需要在类型名称后面加上协议名称,中间以冒号:分隔,作为类型定义的一部分。遵循多个协议时,各协议之间用逗号,分隔。
struct SomeStructure: FirstProtocol, AnotherProtocol {
// 结构体内容
}
如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔。
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 类的内容
}
对属性的规定
协议用于指定特定的实例属性或类属性,而不用指定是存储型属性或计算型属性。此外还必须指明是只读的还是可读可写的。
协议中的通常用var来声明变量属性,在类型声明后加上{ set get }来表示属性是可读可写的,只读属性则用{ get }来表示。
对Mutating方法的规定
有时需要在方法中改变他的实例。
例如,值类型(结构体,枚举)的实例方法中,将mutating关键字作为函数的前缀,写在func之前,表示可以在该方法中修改它所属的实例及其实例属性的值。
对构造器的规定
协议可以要求它的遵循者实现指定的构造器。
你可以像书写普通的构造器那样,在协议的定义里写下构造器的声明,但不需要写花括号和构造器的实体,语法如下:
protocol SomeProtocol {
init(someParameter: Int)
}
协议构造器规定在类中的实现
你可以在遵循该协议的类中实现构造器,并指定其为类的指定构造器或者便利构造器。在这两种情况下,你都必须给构造器实现标上required
修饰符。
protocol tcpprotocol {
init(aprot: Int)
}
class tcpClass: tcpprotocol {
required init(aprot: Int) {
}
}
使用required
修饰符可以保证:所有的遵循该协议的子类,同样能为构造器规定提供一个显示的实现或继承实现。如果一个子类重写了父类的指定构造器,并且该构造器遵循了某个协议的规定,那么该构造器的实现需要被同时标识required
和override
修饰符。
协议类型
尽管协议本身并不实现任何功能,但是协议可以被当作类型来使用。
协议可以像其他普通类型一样使用,使用场景:
- 作为函数,方法或构造器中的参数类型或返回值类型。
- 作为常量,变量或属性的类型
- 作为数组,字典或其他容器的元素类型。
在扩展中添加协议成员
我们可以通过扩展来扩充已存在的类型(类,结构体,枚举等)。扩展可以为已存在的类型添加属性,方法,下标脚本,协议等成员。
协议的继承
协议能够继承一个或多个其他协议,可以在继承的协议基础上增加新的内容要求。协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔。
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// 协议定义
}
类专属协议
在协议的继承列表中,通过添加class
关键字,限制协议只能适配到类(class)类型。该class
关键字必须是第一个出现在协议的继承列表中,其后,才是其他继承协议。
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// 协议定义
}
协议合成
Swift支持合成多个协议,这在我们需要同时遵循多个协议时非常有用。
语法:
protocol<SomeProtocol, AnotherProtocol>
eg:
func show(celebrator: protocol<Stname, Stage>) {
print("\(celebrator.name) is \(celebrator.age) years old")
}
检验协议的一致性
可以使用is
和as
操作符来检查是否遵循某一个协议或强制转化为某一类型。
-
is
操作符用来检查实例是否遵循了某个协议。 -
as?
返回一个可选值,当实例遵循协议时,返回该协议类型。否则返回nil. -
as
用以强制向下转型,如果强转失败,会引起运行时错误。
Swift泛型
Swift提供了泛型让你写出灵活且可用的函数和类型。
Swift标准库是通过泛型代码构建出来的。
Swift的数组和字典类型都是泛型集。
你可以创建一个Int数组,也可以创建一个String数组,或者甚至可以是任何其他Swift的类型数据数组。
func exchange<T>(inout a: T, inout b: T) {
let temp = a
a = b
b = temp
}
这个函数的泛型版本使用了占位类型名字(通常此情况下用字母T来表示)来代替实际类型名(如Int、String或Double)。占位类型名没有提示T必须是什么类型,但是它提示了a和b必须是同一类型T,而不管T表示什么类型。只有 exchange(::)函数在每次调用时所传入的实际类型才能决定T所代表的类型。
泛型类型
Swift允许你定义自己的泛型类型。
扩展泛型类型
当使用extension
扩展一个泛型类型的时候,并不需要在扩展的定义中提供类型参数列表。更加方便的是,原始类型定义中申明的类型参数列表在扩展里是可以使用的,并且这些来自原始类型中的参数名称会被用作原始定义中类型参数的引用。
类型约束
类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。
类型约束语法
你可以写一个在一个类型参数名后面的类型约束,用冒号分隔,来作为类型参数链的一部分。
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// 这里是函数主体
}
关联类型实例
Swift中使用typealias
关键字来设置关联类型。
定义一个协议时,有时候声明一个或多个关联类型作为协议定义的一部分是非常有用的。
where语句
类型约束能够确保类型符合泛型函数或类的定义约束。
在参数列表中通过where
语句定义参数的约束。
写一个where
语句,紧跟在类型参数列表后面,where语句后面跟一个或多个针对关联类型的约束,以及一个或多个类型和关联类型间的等价关系。
Swift访问控制
访问控制可以限定其他源文件或模块中代码对你代码的访问级别。
你可以明确的给单个类型(类,结构体,枚举)设置访问级别,也可以给这些类型的属性,函数,初始化方法,基本类型,下标索引等设置访问级别。
协议也可以被限定在一定的范围内使用,包括协议里的全局常量,变量和函数。
访问控制基于模块和源文件。
模块值得是以独立单元构建和发布的Framework或Application。在Swift中的一个模块可以使用import
关键字引入另一个模块。
源文件是单个源码文件,他通常属于一个模块,源文件可以包含多个类和函数的定义。
Swift为代码中的实体提供了三种不同的访问级别:public,internal,private.
- public: 可以访问自己模块中源文件里的任何实体,别人也可以通过引入该模块来访问源文件里的所有实体。访问级别最高。
- internal: 可以访问自己模块中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。
- private: 只能在当前源文件中使用的实体,称为私有实体。访问级别最低。
除非有特殊的说明,否则实体都使用默认的访问级别internal。
函数类型访问权限
函数的访问级别需要根据该函数的参数类型和返回类型的访问级别得出。如果不是默认权限,必须明确声明该函数。
枚举类型访问权限
枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员单独声明不同的访问级别。
子类访问权限
子类的访问级别不得高于父类的访问级别。比如,父类的访问级别是internal,子类的级别不能声明为public。
常量、变量、属性、下标访问权限
常量、变量、属性不能拥有比它们的类型更高的访问级别。
比如说,你定义一个public级别的属性,但是它的类型是private级别的,这是编译器所不允许的。
同样,下标也不能拥有比索引类型或返回类型更高的访问级别。
如果常量、变量、属性、下标索引的定义类型是private级别的,那么它们必须要明确的申明访问级别为private:private var privateInstance = SomePrivateClass()
构造器和默认构造器访问权限
初始化
我们可以给自定义的初始化方法申明访问级别,但是不要高于它所属类的访问级别。但是必要构造器例外,它的访问级别必须和所属类的访问级别相同。初始化方法的参数的访问级别也不能低于初始化方法的访问级别。
默认初始化方法
Swift为结构体、类都提供了一个默认的无参初始化方法,用于给它们的所有属性提供赋值操作,但不会给出具体值。
默认初始化方法的访问级别与所属类型的访问级别相同。
协议访问权限
如果想为一个协议明确的申明访问级别,那么需要注意一点,就是你要确保该协议只在你申明的访问级别作用域中使用。
如果你定义了一个public访问级别的协议,那么实现该协议提供的必要函数也会是public的访问级别。这一点不同于其他类型,比如,public访问级别的其他类型,他们成员的访问级别为internal。
扩展访问权限
你可以在条件允许的情况下对类、结构体、枚举进行扩展。扩展成员应该具有和原始类成员一致的访问级别。比如你扩展了一个公共类型,那么你新加的成员应该具有和原始成员一样的默认的internal访问级别。
或者,你可以明确申明扩展的访问级别(比如使用private extension)给该扩展内所有成员申明一个新的默认访问级别。这个新的默认访问级别仍然可以被单独成员所申明的访问级别所覆盖。
泛型访问权限
泛型类型或泛型函数的访问级别取决于泛型类型、函数本身、泛型类型参数三者中的最低访问级别。
类型别名
任何你定义的类型别名都会被当作不同的类型,以便于进行访问控制。一个类型别名的访问级别不可高于原类型的访问级别。
比如说,一个private级别的类型别名可以设定给一个public、internal、private的类型,但是一个public级别的类型别名只能设定给一个public级别的类型,不能设定给internal或private 级别的类型。
注意:这条规则也适用于为满足协议一致性而给相关类型命名别名的情况。
参考: