使用包装器时出现奇怪的SequenceType行为

时间:2016-06-17 21:40:46

标签: swift

我有一个包装序列的包装器:

struct SequenceWrapper<T>: SequenceType {
    var sequence: AnySequence<T>

    func generate() -> AnyGenerator<T> {
        return sequence.generate()
    }
}

let wrapper = SequenceWrapper(sequence: AnySequence(1 ... 10))

如果我制作两个生成器并在两者上调用next(),则不会发生任何奇怪的事情:

let generator = wrapper.generate()
let another = wrapper.generate()

generator.next() // 1
another.next()   // 1

到目前为止,这么好。但是,如果我首先在我的包装器上调用dropFirst(),我会遇到奇怪的行为:

let wrapper = SequenceWrapper(sequence: AnySequence(1 ... 10))
let trimmed = wrapper.dropFirst()

let generator = trimmed.generate()
let another = trimmed.generate()

generator.next() // 2
another.next()   // 3, huh?

如果我使用dropLast()代替dropFirst(),则输出为11,如预期的那样。

如果我不使用我制作的包装struct,而是使用直接AnySequence实例,则不会发生任何异常情况:

let sequence = AnySequence(1 ... 10)
let trimmed = sequence.dropFirst()

let generator = trimmed.generate()
let another = trimmed.generate()

generator.next() // 2
another.next()   // 2, as expected

我无法理解这一点。这里发生了什么?

2 个答案:

答案 0 :(得分:2)

您必须通过行为进行调试才能了解具体行为,但最有可能的原因是SequenceTypenot required to be iterable multiple times

  

SequenceType对要求的符合类型没有要求   他们是否会破坏性地消费&#34;通过迭代。确保   非破坏性迭代,将您的序列约束为CollectionType

     

因此,不可能在序列上运行多个for循环来恢复&#34;迭代:

for element in sequence {
  if ... some condition { break }
}

for element in sequence {
  // Not guaranteed to continue from the next element.
  // [mine: not guaranteed to restart from the beginning either]
}
     

SequenceType对此案例中的行为没有要求。它   假设一个序列是&#34;消耗品&#34;是不正确的。   并将恢复迭代,或序列是一个集合,并将   从第一个元素重新开始迭代。一致的序列   不是一个集合是允许产生任意序列的   来自第二个发电机的元件。

换句话说,您从调用generate()两次获得的两个生成器不能保证不会相互干扰。事实上,实现SequenceTypeGeneratorType并将generate()实现为return self的类型是合法的。任何共享状态(来自成员引用,或者如果序列本身是引用类型)将在生成器之间共享,这就是为什么你应该只创建一个。

答案 1 :(得分:0)

内部dropFirst()方法返回AnySequence的新实例(正如您在此行中所见:https://github.com/apple/swift/blob/master/stdlib/public/core/Sequence.swift#l1070)。

您需要添加到SequenceWrapper的内容是以下几行:

func dropFirst() -> SequenceWrapper.SubSequence {
    return sequence.dropFirst()
}

以下是用于测试的简短Playground代码段:

struct SequenceWrapper<T>: SequenceType {
    var sequence: AnySequence<T>

    func generate() -> AnyGenerator<T> {
        return sequence.generate()
    }

    func dropFirst() -> SequenceWrapper.SubSequence {
        return sequence.dropFirst()
    }
}

let wrapper = SequenceWrapper(sequence: AnySequence(1 ... 10))
var generator = wrapper.generate()
var another = wrapper.generate()

generator.next() // 1
another.next()   // 1

var trimmed = wrapper.dropFirst()

generator = trimmed.generate()
another = trimmed.generate()

generator.next() // 2
another.next() // 2! :)