当 Self 实现 IteratorProtocol 时,Swift 如何推断 Sequence 需求?

How does Swift infer Sequence requirements when Self implements IteratorProtocol?

提问人:3366784 提问时间:11/23/2020 最后编辑:3366784 更新时间:11/24/2020 访问量:137

问:

我正在阅读 Sequence 文档,并在他们使用的示例(见下文)中推断出 Sequence 的要求。我的问题是它是如何推断的。我了解推理在更简单的情况下是如何工作的,但在这个例子中,我无法理解 Swift 是如何推断事物的。

我看到 Sequence 的 makeIterator 方法有一个默认实现,但我不明白这里是如何推断返回值的。

struct Countdown: Sequence, IteratorProtocol {

    var count: Int

    mutating func next() -> Int? {
        if count == 0 {
            return nil
        } else {
            defer { count -= 1 }
            return count
        }
    }
}

上述类型的参考

IteratorProtocol {

   func next() -> Self.Element?

   associatedtype Iterator

   associatedtype Element
}
Sequence {

   func makeIterator() -> Self.Iterator

   associatedtype Iterator

   associatedtype Element

}
swift 协议 类型推断

评论

1赞 Sweeper 11/23/2020
您似乎在 的声明中犯了复制粘贴错误。Sequence
0赞 3366784 11/24/2020
@Sweeper谢谢,我刚刚编辑了

答:

1赞 Sweeper 11/23/2020 #1

让我们从 的实现开始。编译器看到以下实现:IteratorProtocol.next

mutating func next() -> Int? {
    if count == 0 {
        return nil
    } else {
        defer { count -= 1 }
        return count
    }
}

并注意到它返回一个 .那么,IteratorProtocol.next 应该返回一个 ,所以它推断 .现在满足.Int?Self.Element?IteratorProtocol.Element == IntCoundownIteratorProtocol

请注意,并共享关联的类型。一旦 Swift 找出了 的见证人,就好像你在 中声明了一个新的类型别名,而恰好需要它存在。SequenceIteratorProtocolElementIteratorProtcol.ElementElementCountdownSequenceCountdown.Element

之后,编译器推断 .这样一来,默认实现 是可用的。然而,编译器如何推断这一点是一个谜,因为只有这些信息,通常无法推断类型,这可以通过创建自己的序列和迭代器协议来证明。Iterator == SelfmakeIterator

protocol MyIterator {
    associatedtype Element
    
    mutating func next() -> Element?
}

protocol MySequence {
    associatedtype Element where Element == Iterator.Element
    associatedtype Iterator : MyIterator
    
    func makeIterator() -> Iterator
}

extension MySequence where Self == Self.Iterator {
    func makeIterator() -> Iterator {
        return self
    }
}

struct Countdown: MySequence, MyIterator { // doesn't compile
    var count: Int

    mutating func next() -> Int? {
        if count == 0 {
            return nil
        } else {
            defer { count -= 1 }
            return count
        }
    }
}

在查看了源代码之后,我怀疑可能会有一些编译器的魔力,尤其是这里:

// Provides a default associated type witness for Iterator when the
// Self type is both a Sequence and an Iterator.
extension Sequence where Self: IteratorProtocol {
  // @_implements(Sequence, Iterator)
  public typealias _Default_Iterator = Self
} 

这似乎设置了一个“首选”类型,以便推断为。它似乎在说“当不能推断为任何东西时,请尝试”。我在其他任何地方都找不到,这就是为什么我得出结论,这是编译器的魔力。这样做的全部目的是让您通过仅遵守和实现 来遵守,正如文档所说的那样。IteratorIteratorSelf_Default_IteratorSequenceIteratorProtocolnext

现在,我们也满足了以下条件的约束:Iterator == SelfElement

associatedtype Element where Self.Element == Self.Iterator.Element

因此,我们已经证明符合 。CountdownSequence

评论

0赞 3366784 11/24/2020
我可能已经想通了。如果我们实现 Sequence,我们会将 typealias Iterator 设置为 Self,因为 CountDown 是一个迭代器,而 Swift 可以推断 Self 是它自己的迭代器。虽然,你对编译器的神奇事情有一个好的观点。正如你所指出的,也许你可以重新表述你的答案,以突出编译器推断它的观点,因为它知道 self 是一个迭代器。我将其标记为正确
0赞 Sweeper 11/24/2020
@3366784我不确定你的意思,但无论如何我已经尽力了,还是编辑了。请随时建议自己编辑:)