如何在 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,
我有一个像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,