0Pricing
Swift Academy · 课时

泛型下标与扩展

为下标和扩展应用约束。

泛型下标与扩展 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

泛型下标

下标可以是泛型的,拥有独立于外围类型的类型参数。这样,一个下标就可以服务于多种输入类型。

struct Lookup {
    let data = [1, 2, 3, 4, 5]
    subscript<S: Sequence>(indices idx: S) -> [Int] where S.Element == Int {
        idx.map { data[$0] }
    }
}
print(Lookup()[indices: [0, 2, 4]])

为什么使用泛型下标

由于同一个下标接受任意由 Int 组成的 Sequence,因此您可以向它传入索引的 Array、Set 或 Range。

struct Lookup {
    let data = [10, 20, 30, 40]
    subscript<S: Sequence>(_ idx: S) -> [Int] where S.Element == Int {
        idx.map { data[$0] }
    }
}
let l = Lookup()
print(l[0...1])
print(l[[3, 0]])

受约束的扩展

extension ... where 会添加仅在约束成立时存在的成员。只有泛型参数匹配时,这些成员才会出现在该类型上。

extension Array where Element: Numeric {
    func sumAll() -> Element { reduce(0, +) }
}
print([1, 2, 3].sumAll())
print([1.5, 2.5].sumAll())

针对特定元素类型的扩展

使用 where Element == String,即可只为字符串数组添加针对 String 的辅助功能。

extension Array where Element == String {
    func shout() -> [String] { map { $0.uppercased() + "!" } }
}
print(["hi", "bye"].shout())

使用协议的受约束扩展

当元素遵循自定义协议时添加相应行为。

protocol Priced { var price: Double { get } }
struct Item: Priced { let price: Double }
extension Collection where Element: Priced {
    var total: Double { reduce(0) { $0 + $1.price } }
}
print([Item(price: 2), Item(price: 3)].total)

返回 Optional 的泛型下标

下标可以是泛型的,并返回可选值,例如安全地对集合进行索引。

extension Array {
    subscript(safe i: Int) -> Element? {
        indices.contains(i) ? self[i] : nil
    }
}
print([1, 2, 3][safe: 1] ?? -1)
print([1, 2, 3][safe: 9] ?? -1)

Dictionary 上的泛型下标

泛型下标可以接受键的序列,并返回匹配的值。

extension Dictionary {
    subscript<S: Sequence>(keys ks: S) -> [Value] where S.Element == Key {
        ks.compactMap { self[$0] }
    }
}
let d = ["a": 1, "b": 2, "c": 3]
print(d[keys: ["a", "c"]].sorted())

与 Self 上的 where 结合

泛型类型的扩展可以约束被包装的类型,从而提供针对性的 API。

struct Stack<T> { var items: [T] = [] }
extension Stack where T: Comparable {
    var peakMax: T? { items.max() }
}
var s = Stack<Int>(); s.items = [3, 9, 1]
print(s.peakMax!)

包含多个参数的泛型下标

下标可以同时接受多个参数和自身的类型参数。

struct Grid {
    let rows = [[1, 2], [3, 4]]
    subscript(_ r: Int, _ c: Int) -> Int { rows[r][c] }
}
print(Grid()[1, 0])

只读与读写

与属性一样,下标可以只有 get,也可以同时具有用于修改的 get 和 set。

struct Pad {
    var values = [0, 0, 0]
    subscript(i: Int) -> Int {
        get { values[i] }
        set { values[i] = newValue }
    }
}
var p = Pad(); p[1] = 7
print(p.values)

综合运用

泛型下标与受约束的扩展结合起来,可以构建表达力强且类型安全的 API,并适应所使用的各种元素类型或参数类型。

extension Array where Element: Comparable {
    subscript(topAfterSort i: Int) -> Element { sorted()[i] }
}
print([5, 1, 9, 3][topAfterSort: 0])

快速检查

请检查您对泛型下标和受约束扩展的理解。

回顾

泛型下标声明自己的类型参数和 where 子句,因此一个下标就可以接受多种输入类型。受约束的扩展(where Element: ... 或 == ...)仅在条件满足时添加成员。两者结合后,可以构建类型安全且适应性强的 API。

常见问题解答

「泛型下标与扩展」课时是免费的吗?

是的 — 「泛型下标与扩展」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「泛型下标与扩展」这节课中我会学到什么?

为下标和扩展应用约束。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「泛型下标与扩展」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 类型参数约束
  2. 函数上的 where 子句
  3. 约束关联类型
  4. 泛型下标与扩展
← 返回 Swift Academy