每当我初次翻看某文档时,我都走马观花似的快速阅过,还一边点着头一边喃喃自语说:“好!懂了,就这么回事!”,可是过后当我真正要运用到这些我以为已经理解了的知识点时,却发现实际情况和我想的往往不一样,每当这时我就懵了,心想:“哇哦…怎么回事?这和我想的完全不一样啊!文档里有说这事吗?”。
最近的几次讨论促使我扪心自问是否真正的理解了Swift中的扩展。我阅读过关于扩展的文档,并且我“认为”我自己对这块内容已经是理解的相当透彻了。可是这几次讨论,加上自己私下通过敲代码的验证,让我发现了我原先不曾注意到几个微妙的细节。
更新:这篇文章刚一发表,Swift社区就出手襄助并帮助我弄明白了我最根本的纠结点在哪。为此,我写了另一篇文章“阐明Swift访问控制”进一步说明我之前的误解。为了避免犯我曾今犯过的错误,我建议大家去读一读。
三个关于扩展的微妙细节
对下面列出的三个细节的思考严重挑战了我之前对Swift扩展的理解:
-
Swift扩展对它所扩展类型的visibility。比如,扩展能访问被private所修饰的内容吗?
-
定义扩展的位置是否对扩展的visibility有影响。比如我这有一个类型我想写个扩展,把扩展写在同一个源文件里和把扩展写在另一个文件里有什么区别吗?
在我开始之前,假设我有一个公共结构体Person。这个结构体有一些私有属性,name,gender,和age。用一个枚举把Gender封装了一下。这个结构体看起来如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
publicstructPerson{
private
var
name:String
gender:Gender
age:Int
publicinit(name:String,gender:Gender,age:Int){
self.name=name
self.gender=gender
self.age=age
}
publicfunchowOldArdYou()->String{
return
formattedAge()
}
//私有方法,用于下面分析扩展的`visibility`...
privatefuncformattedAge()->String{
switch
self.gender{
case
.Male:
return
"I'm\(self.age)."
.Female:
"Nottelling."
}
}
publicenumGender{
Male
Female
}
}
|
现在,就让我们给Person写个扩展,通过实践来弄清楚刚刚提到的三个小细节…
扩展对类型的访问能力
当我提出第一个细节时,关于扩展对被扩展类型的访问能力时,我问了一个问题:“扩展能访问到被private修饰的内容吗?”。答案一开始出乎我的预料:能…扩展能访问到。
然而,这里就要考虑到第二个细节所涉及的问题,那就是:在哪里定义这个扩展是绝对有影响的。
如果扩展和类型是在写同一个源文件里,则扩展能访问到在类型中被priavte所修饰的内容。
举个栗子,在Person.swift里定义一个Person的扩展就会允许这个扩展访问被private修饰的变量和方法
extensionPerson{
funcgetAge()->Int{
age
//尽管age是--private--,但编译成功
}
funcgetFormattedAge()->String{
formattedAge()
//尽管formattedAge是--private--,但编译成功
}
至于为什么把扩展写在同一个源文件里头会这样,我自己的推理是其实可以在写类型的时候,就把扩展的implementation当作类型的一部分给写了,这样的最终效果是一样的。“这谁知道?!什么??为啥?”,我当时就没想明白… |