Swift下表和方法
本文将同时阐述Swift的方法和下标,因为根据我的理解,从某种程度上讲,下标的本质也是方法。
方法
众所周知,在支持面向对象的语言里,方法一般分为两种:实例方法和类方法(在有的语言中,「类方法」被称为「静态方法」)。
Swift也不例外,只是考虑到类、结构体和枚举都可以定义这两种方法,所以「类方法」这个名词在Swift中不太实用了,Swift方法分为「实例方法」和「类型方法」。
实例方法
实例方法的形参名
实例方法和函数差不多(实例方法本来就是函数,只是这个函数与某个类型相关联),细节方面的东西就不赘述了(具体的参考Swift Functions);但有两点不同:
- 相对于函数,Swift对实例方法的形参名要求更多;
- 在实例方法中,常常会用到一个关键的属性
self
;
举个栗子,如下Counter类定义了三个实例方法:
class Counter { var count = 0 func increment() { ++count } func incrementBy(amount: Int) { count += amount } func reset() { count = 0 } }
Swift中的方法和OC中的方法极其相似。像在OC中一样,Swift中方法的名称通常用一个介词指向方法的第一个参数,比如:with,for,by等等。前面的Counter类的例子中incrementBy方法就是这样的,介词的使用让方法在被调用时能像一个句子一样被解读。和函数参数不同,对于方法的参数,Swift使用不同的默认处理方式,这可以让方法命名规范更容易写。
具体来说,Swift默认仅给方法的第一个参数提供一个内部参数名;默认同时给第二个和后续的参数提供内部参数名和外部参数名。这个约定与典型的命名和调用约定相适应,与你在写OC的方法时很相似。这个约定还让表达式方法在调用时不需要再限定参数名称。
简单来说,Swift为实例方法提供的默认处理是:
- 为第一个参数仅提供内部参数名(local parameter name);
- 为第二个以及之后的参数同时提供外部参数名和内部参数名;
如下:
class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes: Int) { count += amount * numberOfTimes } } // 使用 let counter = Counter() counter.incrementBy(5, numberOfTimes: 3) // counter value is now 15
可以看到,不必为第一个参数再定义一个外部变量名:因为从函数名incrementBy已经能很清楚地看出它的作用。但是第二个参数,就要被一个外部参数名称所限定,以便在方法被调用时明确它的作用。
这种默认的行为能够有效的处理方法(method),类似于在参数numberOfTimes前写一个#
:
func incrementBy(amount: Int, #numberOfTimes: Int) { count += amount * numberOfTimes }
但有时候我们不想使用Swift对实例方法参数名的处理方式,解决方法:
- 为第一个参数提供外部参数名,直接添加一个外部参数名即可,或者直接添加
#
; - 取消index>1的参数的外部参数名,在参数名前加上一个
_
即可;
self属性
类型的每一个实例都有一个隐含属性叫做self
,self
完全等同于该实例本身。你可以在一个实例的实例方法中使用这个隐含的self
属性来引用当前实例。
self
的使用比较简单,不赘述了。
Mutable方法
对于值类型(即枚举、结构体)实例而言,默认情况下,是不允许在实例方法中修改属性值的(对于引用类型实例则不存在这个问题)。如果实在有需要修改呢?在值类型的实例方法定义式中加上前缀mutating
修饰即可。如下:
struct Point { var x = 0.0, y = 0.0 func isToTheRightOfX(x: Double) -> Bool { return self.x > x } } let somePoint = Point(x: 4.0, y: 5.0) if somePoint.isToTheRightOfX(1.0) { println("This point is to the right of the line where x == 1.0") } // prints "This point is to the right of the line where x == 1.0"
类型方法
实例方法是被类型的某个实例调用的方法。你也可以定义类型本身调用的方法,这种方法就叫做「类型方法」。
类型方法的定义
和Swift的「类型属性」类似,对于值类型,定义「类型方法」时使用关键字static
修饰;对于引用类型,修饰「类型方法」既可以使用static
又可以使用class
,只是前者不允许子类override该方法,后者允许该「类型方法」被子类overridden。
除了定义使用的关键字之外,「类型方法」的其他信息没啥特别的,本文略过!
下标
在Swift中,类、结构体和枚举中都可以定义「下标」(subscripts),可以认为「下标」是访问对象、集合或序列的快捷方式。使用「下标」,你可以基于index设置和读取指定的实例数据,而不需要另外编写其他的逻辑代码。举例来说,用「下标」访问一个数组(Array)实例中的元素可以这样写someArray[index]
,访问字典(Dictionary)实例中的元素可以这样写someDictionary[key]
。
类型可以定义多个subscripts,通过索引值类型的不同来进行重载,而且索引值可以是多个。
下标语法
Swift中的「下标」允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例的指定数据进行访问和赋值。语法类似于「实例方法」和「计算型属性」的混合,与定义「实例方法」类似,「下标」使用subscript
关键字,显式声明传入参数(一个或多个)和返回类型;与「实例方法」不同的是「下标」可以设定为读写或只读,这种方式又有点像计算型属性的getter和setter,如下:
subscript(index: Int) -> Int { get { // return an appropriate subscript value here } set(newValue) { // perform a suitable setting action here } }
使用下标
根据使用场景不同「下标」也具有不同的含义。通常使用「下标」用来访问集合、列表或序列中元素的快捷方式。你可以在你自己特定的类或结构体中自由地实现「下标」来提供合适的功能。例如,Swift的字典实现了通过「下标」来对其实例中存放的值进行存取操作。在「下标」中使用和字典索引相同类型的值,并且把一个字典值类型的值赋值给这个「下标」来为字典设值:
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] numberOfLegs["bird"] = 2
注意:Swift中字典的「下标」实现中,在get部分返回值是Int?,上例中的numberOfLegs字典通过下边返回的是一个Int?
或者说「可选的Int」,毕竟不是每个字典的索引都能得到一个整型值,对于没有设过值的索引的访问返回的结果就是nil;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为nil即可。
Swift的「下标」的类似于C++中「运算符重载」,相对于OC,它算是Swift语言的一个重要特性了,但其使用并不复杂。