Swift 下标脚本
下标脚本 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。
举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写 someArray[index] ,访问字典(Dictionary)实例中的元素可以这样写 someDictionary[key]。
对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。
下标脚本语法及应用
语法
下标脚本允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值。
语法类似于实例方法和计算型属性的混合。
与定义实例方法类似,定义下标脚本使用subscript关键字,显式声明入参(一个或多个)和返回类型。
与实例方法不同的是下标脚本可以设定为读写或只读。这种方式又有点像计算型属性的getter和setter:
subscript(index: Int) -> Int {
get {
// 用于下标脚本值的声明
}
set(newValue) {
// 执行赋值操作
}
}
实例:
class DaysOfAWeek {
private var days = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "saturday"]
subscript (index: Int) -> String{
get{
return days[index] // 声明下标脚本的值
}
set{
days[index] = newValue // 执行赋值操作
}
}
}
let p = DaysOfAWeek()
p[1] = "Mon-Day"
print(p[0], p[1])
运行结果: Sunday Mon-Day
下标脚本选项
下标脚本允许任意数量的入参索引,并且每个入参类型也没有限制。
下标脚本的返回值也可以是任何类型。
下标脚本可以使用变量参数和可变参数。
一个类或结构体可以根据自身需要提供多个下标脚本实现,在定义下标脚本时通过传入参数的类型进行区分,使用下标脚本时会自动匹配合适的下标脚本实现运行,这就是下标脚本的重载。
struct Matrix {
let rows: Int
let columes: Int
var two_dimensionalArray: [Double]
init(row: Int, col: Int) {
self.rows = row
self.columes = col
self.two_dimensionalArray = Array(repeating: 0.0, count: row*col)
}
subscript(rowIndex: Int, colIndex: Int)-> Double{
set{
two_dimensionalArray[(rowIndex * columes)+colIndex] = newValue
}
get{
return two_dimensionalArray[(rowIndex * columes)+colIndex]
}
}
}
var mat = Matrix(row: 3, col: 3) //3行3列
mat[0,0] = 1.0
mat[0,1] = 2.0
mat[1,0] = 3.0
mat[1,1] = 4.0
print(mat[0,0])
print(mat[0,1])
print(mat[1,0])
print(mat[1,1])
运行结果:
1.0
2.0
3.0
4.0
继承
继承我们可以理解为一个类获取了另外一个类的方法和属性。
当一个类继承其它类时,继承类叫子类,被继承类叫超类(或父类)
在 Swift 中,类可以调用和访问超类的方法,属性和下标脚本,并且可以重写它们。
我们也可以为类中继承来的属性添加属性观察器。
重写(Overriding)
子类可以通过继承来的实例方法,类方法,实例属性,或下标脚本来实现自己的定制功能,我们把这种行为叫重写(overriding)。
我们可以使用 override 关键字来实现重写。
访问超类的方法、属性及下标脚本
你可以通过使用super前缀来访问超类的方法,属性或下标脚本。
重写 | 访问方法,属性,下标脚本 |
---|---|
方法 | super.somemethod() |
属性 | super.someProperty() |
下标脚本 | super[someIndex] |
重写方法和属性
重写方法
在我们的子类中我们可以使用 override 关键字来重写超类的方法。
以下实例中我们重写了 show() 方法:
class SuperClass {
func show() {
print("这是超类 SuperClass")
}
}
class SubClass: SuperClass {
override func show() {
print("这是子类 SubClass")
}
}
let superClass = SuperClass()
superClass.show()
let subClass = SubClass()
subClass.show()
重写属性
你可以提供定制的 getter(或 setter)来重写任意继承来的属性,无论继承来的属性是存储型的还是计算型的属性。
子类并不知道继承来的属性是存储型的还是计算型的,它只知道继承来的属性会有一个名字和类型。所以你在重写一个属性时,必需将它的名字和类型都写出来。
注意点:
-
如果你在重写属性中提供了 setter,那么你也一定要提供 getter。
-
如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接通过super.someProperty来返回继承来的值,其中someProperty是你要重写的属性的名字。
重写属性观察器
你可以在属性重写中为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会监测到。
注意:你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。
防止重写
我们可以使用final关键字防止它们被重写。
如果你重写了final方法,属性或下标脚本,在编译时会报错。
你可以通过在关键字class前添加final特性(final class)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。
class GrandFather {
var height = 0.0
//final 防止重写
final var habit = "喝酒"
var bodyDescript: String{//只读计算类型
return "身高是\(height)cm"
}
}
class Father: GrandFather {
var weight = 0.0
//重写属性
//Cannot override mutable property with read-only property 'habit'
// override var habit: String{
// return "抽烟"
// }
override var bodyDescript: String{
let classString = (NSStringFromClass(type(of: self)))
let splits = classString.split(separator: ".")
return "\(splits[1])"+super.bodyDescript+"体重是\(weight)kg"
}
}
class Son: Father {
override var height: Double{
//重写属性观察器
didSet{//被重写不能为常亮或者只读计算类型
weight = self.height*0.45
}
}
}
let father = Father()
father.height = 170.0
father.weight = 70.0
print(father.bodyDescript)
let son = Son()
son.height = 190.0
print(son.bodyDescript)
运行结果:
Father身高是170.0cm体重是70.0kg
Son身高是190.0cm体重是85.5kg