当我尝试提供自己的 AnySequence 实现时,Swift 无法推断泛型类型

标签 swift generics swift-protocols type-erasure associated-types

问题是当一个协议(protocol)通过其关联类型依赖于另一个协议(protocol)时,编译器无法推断泛型类型。

所以,我一直在研究 Swift 的类型删除技术,试图熟悉它的想法。在我接触到 Sequence 协议(protocol)之前,基本上它是可以理解的。众所周知,它有一个关联类型——Iterator,它符合IteratorProtocol。也就是说,我一直在尝试在我自己的实现中实现类似的行为。这就是我所做的:

final class CustomAnySequence<Element>: Sequence {

    class CustomAnyIterator<Element>: IteratorProtocol {
        private let _next: () -> Element?

        init<I: IteratorProtocol>(_ iterator: I) where I.Element == Element {
            var iterator = iterator
            _next = { iterator.next() }
        }

        func next() -> Element? {
            return _next()
        }
    }

    typealias Iterator = CustomAnyIterator<Element>
    typealias Element = Iterator.Element


    private let _makeIterator: () -> Iterator


    init<S: Sequence>(_ sequence: S) where S.Iterator == Iterator {
        _makeIterator = sequence.makeIterator
    }

    func makeIterator() -> Iterator {
        return _makeIterator()
    }

}

let sequence = CustomAnySequence([1, 2, 3])

因此,最后一行给出了以下错误:无法推断通用参数“Element”

然后,如果我尝试通过显式指定元素类型来修复它:

let sequence = CustomAnySequence<Int>([1, 2, 3])

这并没有让它变得更好。下一个 Xcode 投诉是:无法推断通用参数“S”

那是我的错,还是 Swift 类型推断的开销太大了?

实际上,我遇到了另一种可能的实现方式——它使用私有(private)子类包装。我不太喜欢它(这就是我尝试自己做的原因),因为在父类(super class)的实现中存在“ fatal error 必须被子类化”的方法,这些方法无助于清洁代码。此外,我不确定如何通过 CustomAnySequence 的初始化程序实现此功能(我只发现它可以通过制作静态方法实现)。尽管如此,这就是代码:

class CustomAnySequence<Element>: Sequence {
    class Iterator: IteratorProtocol {
        func next() -> Element? {
            fatalError("Must be overriden")
        }
    }

    func makeIterator() -> Iterator {
        fatalError("Must be overriden")
    }
}

private final class CustomAnySequenceImplementation<S: Sequence>: CustomAnySequence<S.Element> {
    final class IteratorImplementation: Iterator {
        var wrapped: S.Iterator

        init(_ wrapped: S.Iterator) {
            self.wrapped = wrapped
        }

        override func next() -> S.Element? {
            return wrapped.next()
        }
    }

    var sequence: S

    init(_ sequence: S) {
        self.sequence = sequence
    }

    override func makeIterator() -> IteratorImplementation {
        return IteratorImplementation(sequence.makeIterator())
    }
}


extension CustomAnySequence {
    static func make<S: Sequence>(_ sequence: S) -> CustomAnySequence<Element> where S.Element == Element {
        return CustomAnySequenceImplementation<S>(sequence)
    }
}

func printInts(_ sequence: CustomAnySequence<Int>) {
    for element in sequence {
        print(element)
    }
}


printInts(CustomAnySequence.make([1, 2, 3]))
printInts(CustomAnySequence.make(Set([4, 5, 6])))

它实际上确实有效,但它看起来有点像样板。 至少,如果您知道如何使用初始化程序改进它,请告诉我。提前致谢!

最佳答案

第一个实现的问题是

let sequence = CustomAnySequence([1, 2, 3])

不满足

中的约束
init<S: Sequence>(_ sequence: S) where S.Iterator == Iterator 

[1, 2, 3] 是一个序列,但它的迭代器类型不是您的 CustomAnyIterator。您真正想要的是传递具有相同元素 类型而不是相同迭代器类型的序列:

init<S: Sequence>(_ sequence: S) where S.Element == Element 

并将sequence.makeIterator()传递给CustomAnyIterator的init方法。

另请注意,内部类可以从外部类继承 Element 类型占位符,并且实际上不需要类型别名。

final class CustomAnySequence<Element>: Sequence {

    class CustomAnyIterator: IteratorProtocol {
        private let _next: () -> Element?

        init<I: IteratorProtocol>(_ iterator: I) where I.Element == Element {
            var iterator = iterator
            _next = { iterator.next() }
        }

        func next() -> Element? {
            return _next()
        }
    }

    private let _makeIterator: () -> CustomAnyIterator

    init<S: Sequence>(_ sequence: S) where S.Element == Element {
        _makeIterator = { CustomAnyIterator(sequence.makeIterator()) }
    }

    func makeIterator() -> CustomAnyIterator {
        return _makeIterator()
    }
}

您也可以考虑使用 struct 而不是 class

关于当我尝试提供自己的 AnySequence 实现时,Swift 无法推断泛型类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57561591/

相关文章:

swift - Rx swift : Use Zip with different type observables

Java泛型和覆盖

java - 将 String 转换为任何所需类的通用代码

swift - 为什么不调用委托(delegate)方法?

swift - AVFoundation AVAudioSourceNode格式似乎是一种 native 格式,与其他AVAudioEngine不同

arrays - 从 Swift 数组中删除自定义类型的集合

java - 为什么Java迭代器构造函数签名没有迭代器类型?

ios - 如何返回实现另一个协议(protocol)的泛型类型

Swift keyPath 与协议(protocol)

ios - 在 google+ IOS Swift 中分享