我有一个String
之类的LINNIIBDDDN
,基本上是一系列令牌。我想使用多个迭代器,每个令牌类型一个。我想让每个迭代器都忽略不属于它的令牌。也就是说,我想调用类似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机制可以执行这种操作?
答案 0 :(得分:2)
String.Iterator
被(隐式)定义为
typealias Iterator = IndexingIterator<String>
和错误消息
必须在具有“ where”子句指定约束的非专业通用类型“ IndexingIterator”上声明受约束的扩展名
意味着我们必须将扩展方法定义为
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,
但是实际上我会考虑将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: { $0 % 2 == 0} ) {
print(e, terminator: ", ")
}
print()
// 2, 8, 34,