Swift5.x -下标(中文文档)

1,396 阅读8分钟

引言

继续学习Swift文档,从上一章节:方法,我们学习了Swift方法相关的内容,如实例方法的定义和使用、mutating关键字的作用、类方法的定义和使用等这些内容。现在,我们学习Swift的下标相关的内容。由于篇幅较长,这里分篇来记录,接下来,Fighting!

如果你已经熟悉这章节内容,请移步下一章节:继承

下标

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

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

1 下标语法

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

subscript(index: Int) -> Int {
    get {
        // Return an appropriate subscript value here.
    }
    set(newValue) {
        // Perform a suitable setting action here.
    }
}

newValue的类型与下标的返回值相同。 与计算属性一样,您可以选择不指定设置者的(newValue)参数。 如果您自己没有提供一个默认参数,名称为newValue则会提供给设置器。

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

subscript(index: Int) -> Int {
    // Return an appropriate subscript value here.
}

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

struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// Prints "six times three is 18"

在此示例中,创建了一个TimesTable的新实例来表示三倍表。 这是通过将值3传递给结构的初始值设定项来表示的,该值用于实例的multiplier参数。

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

注意
n次表基于固定的数学规则。 将ThreeTimesTable [someIndex]设置为新值是不合适的,因此TimesTable的下标定义为只读下标。

2 下标用法

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

例如,Swift的Dictionary类型实现下标以设置和检索存储在Dictionary实例中的值。 您可以在字典中设置值,方法是在下标括号内提供字典的键类型的键,然后将字典的值类型的值分配给下标:

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

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

有关字典下标的更多信息,请参见Accessing and Modifying a Dictionary

Swift的Dictionary类型将其键值下标实现为采用并返回可选类型的下标。 对于上面的numberOfLegs词典,键值下标采用并返回类型为Int?或“ optional int”的值。 字典类型使用可选的下标类型来对并非每个键都具有值的事实进行建模,并通过为该键分配nil值来提供一种删除键值的方法。

3 下标选项

下标可以采用任意数量的输入参数,并且这些输入参数可以是任何类型。下标还可以返回任何类型的值。

像函数一样,下标可以采用不同数量的参数,并为其参数提供默认值,如Variadic ParametersDefault Parameter Values中所述。但是,与函数不同,下标不能使用输入输出参数。

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

虽然下标采用单个参数是最常见的,但是如果适合您的类型,则还可以定义带有多个参数的下标。下面的示例定义一个Matrix结构体,该结构体表示Double值的二维矩阵。矩阵结构的下标带有两个整数参数:

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, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}

Matrix提供了一个初始化器,该初始化器接受称为行和列的两个参数,并创建一个足够大的数组来存储行*列类型为Double的值。 矩阵中的每个位置的初始值均为0.0。 为此,将数组大小和初始单元格值0.0传递给数组初始化程序,该初始化程序创建并初始化正确大小的新数组。 使用Creating an Array with a Default Value将详细描述此初始化程序。

您可以通过将适当的行数和列数传递给其初始化程序来构造新的Matrix实例:

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

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

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

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

这两个语句调用下标的设置器,以在矩阵的右上位置(行为0,列为1)设置值为1.5,在左下角位置(行为1,列为0)设置值为3.2:

Matrix下标的getter和setter都包含一个断言,以检查下标的行和列值是否有效。 为了帮助进行这些声明,Matrix包含了一个便捷的方法,称为indexIsValid(row:column :),该方法检查所请求的行和列是否在矩阵的范围内:

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

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

let someValue = matrix[2, 2]
// This triggers an assert, because [2, 2] is outside of the matrix bounds.

4 类型下标

如上所述,实例下标是您在特定类型的实例上调用的下标。 您还可以定义在类型本身上调用的下标。 这种下标称为类型下标。 您可以通过在下标关键字之前写入static关键字来指示类型下标。 类可以改为使用class关键字,以允许子类覆盖父类对该下标的实现。 以下示例显示了如何定义和调用类型下标:

enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    static subscript(n: Int) -> Planet {
        return Planet(rawValue: n)!
    }
}
let mars = Planet[4]
print(mars)

总结

这一章节主要讲的是可以使用subscript语法为类、结构体和枚举定义下标语法,这样类、结构体和枚举就可以和数组、字典一样使用下标来查询和设置对应索引的值。主要的内容:

  • 下标语法
  • 下标的用法
  • 下标的选项:可以像函数那样,传入多个参数来对多个下标的场景的应用。
  • 类型下标:和类型属性和类方法一样,使用static关键词修饰下标语法。

最后,有收获的朋友麻烦点个赞呦,谢谢~

上一章节:方法

下一章节:继承

参考文档: Swift - Subscripts