代码之家  ›  专栏  ›  技术社区  ›  SaganRitual

如何在Swift中扩展String.Iterator

  •  4
  • SaganRitual  · 技术社区  · 6 年前

    我有一个 String 喜欢 LINNIIBDDDN ,基本上是一系列的代币。我想使用多个迭代器,每个令牌类型一个迭代器。我想让每个迭代器忽略不属于它的标记。也就是说,我想打电话给 next_ish() ,使迭代器前进到其特定标记的下一个元素。所以如果 N 迭代器在索引3处,我调用 下一步() ,我要它转到索引10,下一个 N ,而不是 I 在索引4,我有一些代码已经可以工作了,但是代码太多了,这使得 一串 在数组中,我有子类迭代器,基本上是手工编写的,没有Swift的帮助,尽管我确信Swift迭代器更稳定,测试也更彻底。如果可能的话,我宁愿使用他们的代码而不是我的。

    似乎只要延伸就可以了 String.Iterator 并添加 下一步() ,但我不知所措。我第一次天真的尝试是 . 我得到了错误 Constrained extension must be declared on the unspecialized generic type 'IndexingIterator' with constraints specified by a 'where' clause where 我什么也没找到。

    这里有很多答案,关于扩展数组和泛型,将某个类型的所有元素拉入它们自己的数组,甚至还有一些关于专门化的答案 for...in 循环,但我找不到任何关于扩展迭代器的内容。我已经通读了 Collections.swift 字符串迭代器

    1 回复  |  直到 6 年前
        1
  •  2
  •   Martin R    6 年前

    String.Iterator (隐含地)定义为

    typealias Iterator = IndexingIterator<String>
    

    以及错误消息

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

    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
      // ...
    }
    

    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($0) }) {
        print(c, terminator: ", ")
    }
    print()
    // N, n, N,
    

    但实际上我会考虑 成为一个 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: { $0 % 2 == 0} ) {
        print(e, terminator: ", ")
    }
    print()
    // 2, 8, 34,