如何在 Swift 中扩展 String.Iterator

How to extend String.Iterator in Swift

我有一个像LINNIIBDDDN一样的String,基本上是一系列的令牌。我想使用多个迭代器,每个标记类型一个。我想让每个迭代器忽略不属于它的标记。也就是说,我想调用类似 next_ish() 的方法来将迭代器推进到其特定标记的下一个元素。因此,如果 N 迭代器位于索引 3,我调用 next_ish(),我希望它转到索引 10,下一个 N,而不是索引 4 的 I .我有一些代码已经可以工作了,但是代码很多,它把String变成了一个数组,我有子类迭代器,基本上是手写的,没有Swift的帮助,虽然我确信 Swift 迭代器更稳定且经过全面测试。在可能的情况下,我宁愿使用他们的代码也不愿使用我的代码。

似乎只扩展 String.Iterator 并添加 next_ish() 应该很容易,但我不知所措。我的第一个幼稚尝试是扩展 String.Iterator。我收到错误 Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause。我想弄清楚要使用哪种 where 子句,但没有找到任何东西。

这里有很多关于 SO 的答案,关于扩展数组和泛型,将某种类型的所有元素拉到它们自己的数组中,甚至还有一些关于专门的 for...in 循环的答案,但我找不到任何关于扩展迭代器的信息。我通读了 Collections.swift,但没有发现任何有用的信息。是否可以延长 String.Iterator?那会让我的生活轻松很多。如果没有,是否有某种内置的 Swift 机制来执行此类操作?

String.Iterator 被(隐含地)定义为

typealias Iterator = IndexingIterator<String>

和错误信息

Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause

意味着我们必须将扩展方法定义为

extension IndexingIterator where Elements == String { }

或者(随着普遍性的增加):

extension IndexingIterator where Elements: StringProtocol { }
extension IndexingIterator where Elements.Element == Character { }

我还没有找到访问基础集合(或位置)的方法 在扩展方法中,相应的成员定义为 “内部”:

public struct IndexingIterator<Elements : Collection> {
  internal let _elements: Elements
  internal var _position: Elements.Index
  // ...
}

你可以做的是将想要的元素传递给你的“next-ish”方法, 作为元素本身,或作为谓词:

extension IndexingIterator where Elements.Element == Character {

    mutating func next(_ wanted: Character) -> Character? {
        while let c = next() {
            if c == wanted { return c }
        }
        return nil
    }

    mutating func next(where predicate: ((Character) -> Bool)) -> Character? {
        while let c = next() {
            if predicate(c) { return c }
        }
        return nil
    }
}

用法示例:

var it1 = "ABCDABCE".makeIterator()
print(it1.next("C") as Any) // Optional("C")
print(it1.next() as Any)    // Optional("D")
print(it1.next("C") as Any) // Optional("C")
print(it1.next() as Any)    // Optional("E")
print(it1.next("C") as Any) // nil

var it2 = "LINnIIBDDDN".makeIterator()
while let c = it2.next(where: { "Nn".contains([=15=]) }) {
    print(c, terminator: ", ")
}
print()
// N, n, N,

但实际上我会认为 String.Iterator 是一个 IndexingIterator 的实现细节,并改为扩展 IteratorProtocol

extension IteratorProtocol where Element: Equatable {
    mutating func next(_ wanted: Element) -> Element? {
        while let e = next() {
            if e == wanted { return e }
        }
        return nil
    }
}

extension IteratorProtocol  {
    mutating func next(where predicate: ((Element) -> Bool)) -> Element? {
        while let e = next() {
            if predicate(e) { return e }
        }
        return nil
    }
}

这使得它可用于任意序列。示例:

var it3 = [1, 1, 2, 3, 5, 8, 13, 21, 34].makeIterator()
while let e = it3.next(where: { [=17=] % 2 == 0} ) {
    print(e, terminator: ", ")
}
print()
// 2, 8, 34,