IOS开发语言Swift入门连载---下标脚本

IOS开发语言Swift入门连载—下标脚本

下标脚本 可以定义在类(Class)、结构体(structure)和枚举(enumeration)这些目标中,可以认为是访问对象、集合或序列的快捷方式,不需要再调用实例的特定的赋值和访问方法。举例来说,用下标脚本访问一个数组(Array)实例中的元素可以这样写someArray[index] ,访问字典(Dictionary)实例中的元素可以这样写 someDictionary[key] 。

  对于同一个目标可以定义多个下标脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。

  译者:这里附属脚本重载在本小节中原文并没有任何演示

  

下标脚本语法

  下标脚本允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值。语法类似于实例方法和计算型属性的混合。与定义实例方法类似,定义下标脚本使用subscript 关键字,显式声明入参(一个或多个)和返回类型。与实例方法不同的是下标脚本可以设定为读写或只读。这种方式又有点像计算型属性的getter和setter:

subscript(index: Int) -> Int {
    get {
      // 返回与入参匹配的Int类型的值
    }

    set(newValue) {
      // 执行赋值操作
    }
}

  newValue 的类型必须和下标脚本定义的返回类型相同。与计算型属性相同的是set的入参声明newValue 就算不写,在set代码块中依然可以使用默认的newValue 这个变量来访问新赋的值。  与只读计算型属性一样,可以直接将原本应该写在get 代码块中的代码写在subscript 中:

subscript(index: Int) -> Int {
    // 返回与入参匹配的Int类型的值
}

  下面代码演示了一个在TimesTable 结构体中使用只读下标脚本的用法,该结构体用来展示传入整数的n倍。

struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
      return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
println("3的6倍是\(threeTimesTable[6])")
// 输出 "3的6倍是18"

  在上例中,通过TimesTable 结构体创建了一个用来表示索引值三倍的实例。数值3 作为结构体构造函数 入参初始化实例成员multiplier 。  

你可以通过下标脚本来得到结果,比如threeTimesTable[6] 。这条语句访问了threeTimesTable 的第六个元素,返回6 的3 倍即18 。  

注意:  

TimesTable 例子是基于一个固定的数学公式。它并不适合开放写权限来对threeTimesTable[someIndex] 进行赋值操作,这也是为什么附属脚本只定义为只读的原因。  

下标脚本用法

  

根据使用场景不同下标脚本也具有不同的含义。通常下标脚本是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式。你可以在你自己特定的类或结构体中自由的实现下标脚本来提供合适的功能。  

例如,Swift 的字典(Dictionary)实现了通过下标脚本来对其实例中存放的值进行存取操作。在下标脚本中使用和字典索引相同类型的值,并且把一个字典值类型的值赋值给这个下标脚本来为字典设值:

var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2

  上例定义一个名为numberOfLegs 的变量并用一个字典字面量初始化出了包含三对键值的字典实例。numberOfLegs 的字典存放值类型推断为Dictionary 。字典实例创建完成之后通过下标脚本的方式将整型值2 赋值到字典实例的索引为bird 的位置中。  

更多关于字典(Dictionary)下标脚本的信息请参考读取和修改字典  

注意:  

中字典的附属脚本实现中,在get 部分返回值是Int? ,上例中的numberOfLegs 字典通过附属脚本返回的是一个Int? 或者说“可选的int”,不是每个字典的索引都能得到一个整型值,对于没有设过值的索引的访问返回的结果就是nil ;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为nil 即可。  

下标脚本选项

 

下标脚本允许任意数量的入参索引,并且每个入参类型也没有限制。下标脚本的返回值也可以是任何类型。下标脚本可以使用变量参数和可变参数,但使用写入读出(in-out)参数或给参数设置默认值都是不允许的。  

一个类或结构体可以根据自身需要提供多个下标脚本实现,在定义下标脚本时通过入参个类型进行区分,使用下标脚本时会自动匹配合适的下标脚本实现运行,这就是下标脚本的重载。  

下标脚本入参是最常见的情况,但只要有合适的场景也可以定义多个下标脚本入参。如下例定义了一个Matrix 结构体,将呈现一个Double 类型的二维矩阵。Matrix 结构体的下标脚本需要两个整型参数:

struct Matrix {
    let rows: Int, columns: Int
    var grid: Double[]
    init(rows: Int, columns: Int) {
      self.rows = rows
      self.columns = columns
      grid = Array(count: rows * columns, repeatedValue: 0.0)
    }
    func indexIsValidForRow(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

  Matrix 提供了一个两个入参的构造方法,入参分别是rows 和columns ,创建了一个足够容纳rows * columns 个数的Double 类型数组。为了存储,将数组的大小和数组每个元素初始值0.0,都传入数组的构造方法中来创建一个正确大小的新数组。关于数组的构造方法和析构方法请参考创建并且构造一个数组。  

你可以通过传入合适的row 和columns 的数量来构造一个新的Matrix 实例:

var matrix = Matrix(rows: 2, columns: 2)

  上例中创建了一个新的两行两列的Matrix 实例。在阅读顺序从左上到右下的Matrix 实例中的数组实例grid 是矩阵二维数组的扁平化存储:

// 示意图
grid = [0.0, 0.0, 0.0, 0.0]

      col0  col1
row0   [0.0,     0.0,
row1    0.0,  0.0]

  将值赋给带有row 和column 下标脚本的matrix 实例表达式可以完成赋值操作,下标脚本入参使用逗号分割

matrix[0, 1] = 1.5
matrix[1, 0] = 3.2

  上面两条语句分别让matrix 的右上值为 1.5,坐下值为 3.2:

[0.0, 1.5,
 3.2, 0.0]

  Matrix 下标脚本的getter 和setter 中同时调用了下标脚本入参的row 和column 是否有效的判断。为了方便进行断言,Matrix 包含了一个名为indexIsValid 的成员方法,用来确认入参的row 或column 值是否会造成数组越界:

func indexIsValidForRow(row: Int, column: Int) -> Bool {
    return row >= 0 && row < rows && column >= 0 && column < columns
}

  断言在下标脚本越界时触发:

let someValue = matrix[2, 2]
// 断言将会触发,因为 [2, 2] 已经超过了matrix的最大长度
时间: 2024-07-31 21:07:46

IOS开发语言Swift入门连载---下标脚本的相关文章

IOS开发语言Swift入门连载---可选链

IOS开发语言Swift入门连载-可选链 可选链(Optional Chaining) 是一种可以请求和调用属性.方法及下标脚本的过程,它的可选性体现于请求或调用的目标当前可能为空(nil ).如果可选的目标有值,那么调用就会成功:相反,如果选择的目标为空(nil ),则这种调用将返回空(nil ).多次请求或调用可以被链接在一起形成一个链,如果任何一个节点为空(nil )将导致整个链失效. 注意: 的可选链和 Objective-C 中的消息为空有些相像,但是 Swift 可以使用在任意类型中

IOS开发语言Swift入门连载---类和结构体

IOS开发语言Swift入门连载-类和结构体 类和结构体是人们构建代码所用的一种通用且灵活的构造体.为了在类和结构体中实现各种功能,我们必须要严格按照常量.变量以及函数所规定的语法规则来定义属性和添加方法. 与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件.你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口. 注意: 通常一个类 的实例被称为对象 .然而在Swift 中,类和结构体的关系要比在其他语言中更加的密切,本

IOS开发语言Swift入门连载---继承

IOS开发语言Swift入门连载-继承 一个类可以继承(inherit)另一个类的方法(methods),属性(property)和其它特性.当一个类继承其它类时,继承类叫子类(subclass),被继承类叫超类(或父类,superclass).在 Swift 中,继承是区分「类」与其它类型的一个基本特征. 在 Swift 中,类可以调用和访问超类的方法,属性和下标脚本(subscripts),并且可以重写(override)这些方法,属性和下标脚本来优化或修改它们的行为.Swift 会检查你的

IOS开发语言Swift入门连载---协议

IOS开发语言Swift入门连载-协议 协议(Protocol) 协议(Protocol)用于定义完成某项任务或功能所必须的方法和属性,协议实际上并不提供这些功能或任务的具体实现(Implementation) –而只用来描述这些实现应该是什么样的.类,结构体,枚举通过提供协议所要求的方法,属性的具体实现来采用(adopt) 协议.任意能够满足协议要求的类型被称为协议的遵循者. 协议可以要求其遵循者提供特定的实例属性,实例方法,类方法,操作符或下标脚本等. 协议的语法 协议 的定义方式与类,结构

IOS开发语言Swift入门连载---扩展

IOS开发语言Swift入门连载-扩展 扩展就是向一个已有的类.结构体或枚举类型添加新功能(functionality).这包括在没有权限获取原始源代码的情况下扩展类型的能力(即逆向建模).扩展和 Objective-C 中的分类(categories)类似.(不过与Objective-C不同的是,Swift 的扩展没有名字.) Swift中的扩展可以: 添加计算型属性和计算静态属性 定义实例方法和类型方法 提供新的构造器 定义下标 定义和使用新的嵌套类型 使一个已有类型符合某个协议 注意: 如

IOS开发语言Swift入门连载---闭包

IOS开发语言Swift入门连载-闭包 闭包是自包含的函数代码块,可以在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 lambdas 函数比较相似. 闭包可以捕获和存储其所在上下文中任意常量和变量的引用. 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包.Swift 会为您管理在捕获过程中涉及到的所有内存操作. 注意: 如果您不熟悉捕获(capturing)这个概念也不用担心,您可以在 值捕获 章节对其进行详细了

IOS开发语言Swift入门连载---泛型

IOS开发语言Swift入门连载-泛型 泛型代码可以让你写出根据自我需求定义.适用于任何类型的,灵活且可重用的函数和类型.它的可以让你避免重复的代码,用一种清晰和抽象的方式来表达代码的意图. 泛型是 Swift 强大特征中的其中一个,许多 Swift 标准库是通过泛型代码构建出来的.事实上,泛型的使用贯穿了整本语言手册,只是你没有发现而已.例如,Swift 的数组和字典类型都是泛型集.你可以创建一个Int 数组,也可创建一个String 数组,或者甚至于可以是任何其他 Swift 的类型数据数组

IOS开发语言Swift入门连载---集合类型

IOS开发语言Swift入门连载-集合类型 Swift语言提供经典的数组和字典两种集合类型来存储集合数据.数组用来按顺序存储相同类型的数据.字典虽然无序存储相同类型数据值但是需要由独有的标识符引用和寻址(就是键值对). Swift语言里的数组和字典中存储的数据值类型必须明确. 这意味着我们不能把不正确的数据类型插入其中. 同时这也说明我们完全可以对获取出的值类型非常自信. Swift 对显式类型集合的使用确保了我们的代码对工作所需要的类型非常清楚,也让我们在开发中可以早早地找到任何的类型不匹配错

IOS开发语言Swift入门连载---类型转换

IOS开发语言Swift入门连载-类型转换 类型转换可以判断实例的类型,也可以将实例看做是其父类或者子类的实例. 类型转换在 Swift 中使用is 和 as 操作符实现.这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型. 你也可以用来检查一个类是否实现了某个协议,就像在 Checking for Protocol Conformance部分讲述的一样. 定义一个类层次作为例子 你可以将它用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的