天天看点

Swift编程十三(下标)下标

案例代码下载

下标

类,结构和枚举可以定义下标,下标是用于访问集合,列表或序列的成员元素的快捷方式。可以使用下标按索引设置和检索值,而无需单独的设置和检索方法。例如,可以使用someArray[index]在Array实例中和使用someDictionary[key]在Dictionary实例访问元素。

可以为单个类型定义多个下标,并根据传递给下标的索引值的类型选择要使用的相应下标重载。下标不限于单个维度,可以定义具有多个输入参数的下标,以满足自定义类型的需求。

下标语法

可以通过下标在实例名称后面的方括号中写入一个或多个值来查询类型的实例。它们的语法类似于实例方法语法和计算属性语法。使用subscript关键字编写下标定义,并以与实例方法相同的方式指定一个或多个输入参数和返回类型。与实例方法不同,下标可以是读写或只读。此行为由getter和setter以与计算属性相同的方式传递:

subscript(index: Int) -> Int {
    get {
        // 返回一个适当的下标值
    }
    set(newValue) {
        // 执行相应的设值操作
    }
}
           

newValue类型与下标的返回值相同。与计算属性一样,可以选择不指定setter的(newValue)参数。newValue如果没有自己提供,则setter提供一个默认参数。

与只读计算属性一样,可以通过删除get关键字及其大括号来简化只读下标的声明:

subscript(index: Int) -> Int {
    // 返回一个适当的下标值
}
           

这是一个只读下标实现的示例,它定义了一个TimesTable表示整数n倍数表的结构:

struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print(threeTimesTable[6])
           

在此示例中,TimesTable创建了一个新实例来表示3的倍数表。这通过将3的值传递给结构初始化作为实例multiplier参数的值来表示。

可以通过调用threeTimesTable下标来查询实例,如调用中所示threeTimesTable[6]。这将请求3的倍数表中的第六个条目,该表返回值18或3的6倍。

注意: 一个倍数表是基于一个固定的数学规则。设置threeTimesTable[someIndex]为新值是不合适的,因此TimesTable下标被定义为只读下标。

下标用法

“下标”的确切含义取决于使用它的上下文。下标通常用作访问集合,列表或序列中的成员元素的快捷方式。可以以最合适的方式为特定类或结构的功能实现下标。

例如,Swift的Dictionary类型实现了一个下标来设置和检索存储在Dictionary实例中的值。可以通过在下标括号中提供字典的键类型的键,并将字典的值类型的值分配给下标来设置字典中的值:

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

上面的示例定义了一个名为numberOfLegs的变量,并使用包含三个键值对的字典文字对其进行初始化。numberOfLegs推断字典的类型是[String: Int]。创建字典后,此示例使用下标分配向字典添加键String"bird"和值Int2。

有关Dictionary下标的详细信息,请参阅访问和修改字典。

注意: Swift的Dictionary类型将其键值下标实现为获取并返回可选类型的下标。对于上面的numberOfLegs字典,键值下标采用并返回Int?类型的值,或“optional int”类型。该Dictionary类型使用可选的下标类型来模拟不是每个键都有值的事实,并通过为该键赋值为nil来删除键的值提供一种方法。

下标选项

下标可以采用任意数量的输入参数,这些输入参数可以是任何类型。下标也可以返回任何类型。下标可以使用可变参数,但它们不能使用输入输出参数或提供默认参数值。

类或结构可以根据需要提供尽可能多的下标实现,并且将基于在使用下标处括号内包含的值或值的类型来推断要使用的适当下标。多个下标的这种定义称为下标重载。

虽然下标采用单个参数是最常见的,但如果适合你的类型,也可以定义带有多个参数的下标。以下示例定义了一个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(repeating: 0.0, count: rows*columns)
    }
    func indexIsValid(row: Int, colunm: Int) -> Bool {
        return row >= 0 && row < rows && colunm >= 0 && colunm < columns
    }
    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValid(row: row, colunm: column), "Index out of range")
            return grid[row*columns + column]
        }
        set {
            assert(indexIsValid(row: row, colunm: column), "Index out of range")
            grid[row*columns + column] = newValue
        }
    }
}
           

Matrix提供了采用两个称为rows和columns参数的初始化方法,并创建一个数组,它是大到足以存储rows * columns个Double类型的值。矩阵中的每个位置都给出初始值0.0。为此,将数组的大小和初始单元格值0.0传递给数组初始值设定项,该数组初始值设定项创建并初始化正确大小的新数组。在创建具有默认值的数组中更详细地描述了此初始化程序。

可以通过将适当的行和列计数传递给Matrix初始化设定项来构造新实例:

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

上面的示例创建了一个Matrix包含两行和两列的新实例。此Matrix实例的数组实际上是矩阵的扁平版本,从左上角到右下角读取:

Swift编程十三(下标)下标

可以通过将行和列值传递到下标中来设置矩阵中的值,用逗号分隔:

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

这两个语句调用下标的setter来设置矩阵右上角的位置(其中row是0和column是1)为1.5,并在左下角位置(其中row是1和column是0)设置为3.2:

Swift编程十三(下标)下标

Matrix下标的getter和setter都包含一个断言,以检查标的row和column值是有效的。为了协助这些断言,Matrix包括一个被称为indexIsValid(row:column:)便捷方法,检查是否所请求的row和column处于矩阵的边界内:

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

如果尝试访问矩阵边界之外的下标,则会触发断言:

let someValue = matrix[2, 2]