swift - 类型删除的通用包装器是如何实现的?

标签 swift generics

我需要为我自己的结构实现一个类型删除包装器,非常类似于 SequenceOfGeneratorOf 等。所以我开始尝试重新实现我自己的标准 SequenceOf

我刚刚复制并粘贴了 SequenceOf 的声明,将其重命名为 MySequenceOf,并填写了一些 stub 以获得:

/// A type-erased sequence.
///
/// Forwards operations to an arbitrary underlying sequence with the
/// same `Element` type, hiding the specifics of the underlying
/// sequence type.
///
/// See also: `GeneratorOf<T>`.
struct MySequenceOf<T> : SequenceType {

    /// Construct an instance whose `generate()` method forwards to
    /// `makeUnderlyingGenerator`
    init<G : GeneratorType where T == T>(_ makeUnderlyingGenerator: () -> G) {
        fatalError("implement me")
    }

    /// Construct an instance whose `generate()` method forwards to
    /// that of `base`.
    init<S : SequenceType where T == T>(_ base: S) {
        fatalError("implement me")
    }

    /// Return a *generator* over the elements of this *sequence*.
    ///
    /// Complexity: O(1)
    func generate() -> GeneratorOf<T> {
        fatalError("implement me")
    }
}

我收到编译器错误:“同一类型中的类型均未引用泛型参数或关联类型”。所以我假设 Xcode 生成的 SequenceOf 的“where T == T”约束声明实际上意味着“where G.Element == T”,这给了我以下可编译的结构:

struct MySequenceOf<T> : SequenceType {

    init<G : GeneratorType where G.Element == T>(_ makeUnderlyingGenerator: () -> G) {
        fatalError("implement me")
    }

    func generate() -> GeneratorOf<T> {
        fatalError("implement me")
    }
}

现在,很简单,我只需要从初始化程序中挂起 makeUnderlyingGenerator 并从 generate() 中调用它:

struct MySequenceOf<T> : SequenceType {
    let maker: ()->GeneratorOf<T>

    init<G : GeneratorType where G.Element == T>(_ makeUnderlyingGenerator: () -> G) {
        self.maker = { return makeUnderlyingGenerator() }
    }

    func generate() -> GeneratorOf<T> {
        return self.maker()
    }
}

但这给了我错误:“‘G’不能转换为‘GeneratorOf’

如果我强制转换,它编译:

struct MySequenceOf<T> : SequenceType {
    let maker: ()->GeneratorOf<T>

    init<G : GeneratorType where G.Element == T>(_ makeUnderlyingGenerator: () -> G) {
        self.maker = { return makeUnderlyingGenerator() as GeneratorOf<T> }
    }

    func generate() -> GeneratorOf<T> {
        return self.maker()
    }
}

但随后它会在运行时因动态转换而崩溃。

那么如何实现这样的类型删除呢?这一定是可能的,因为 Swift 标准库做了很多(SequenceOf、GeneratorOf、SinkOf)。

最佳答案

尝试:

struct MySequenceOf<T> : SequenceType {
    private let _generate:() -> MyGeneratorOf<T>

    init<G : GeneratorType where G.Element == T>(_ makeUnderlyingGenerator: () -> G) {
        _generate = { MyGeneratorOf(makeUnderlyingGenerator()) }
    }

    init<S : SequenceType where S.Generator.Element == T>(_ base: S) {
        _generate = { MyGeneratorOf(base.generate()) }
    }

    func generate() -> MyGeneratorOf<T> {
        return _generate()
    }
}

struct MyGeneratorOf<T> : GeneratorType, SequenceType {

    private let _next:() -> T?

    init(_ nextElement: () -> T?) {
        _next = nextElement
    }

    init<G : GeneratorType where G.Element == T>(var _ base: G) {
        _next = { base.next() }
    }

    mutating func next() -> T? {
        return _next()
    }

    func generate() -> MyGeneratorOf<T> {
        return self
    }
}

实现的基本策略ProtocolOf<T>是这样的:

protocol ProtocolType {
    typealias Value
    func methodA() -> Value
    func methodB(arg:Value) -> Bool
}

struct ProtocolOf<T>:ProtocolType {
    private let _methodA: () -> T
    private let _methodB: (T) -> Bool

    init<B:ProtocolType where B.Value == T>(_ base:B) {
        _methodA = { base.methodA() }
        _methodB = { base.methodB($0) }
    }

    func methodA() -> T { return _methodA() }
    func methodB(arg:T) -> Bool { return _methodB(arg) }
}

添加在评论中回答@MartinR。

Is there a special reason that _generate is a closure and not the generator itself?

首先,我认为,这是规范或语义的问题。

不用说,区别在于“何时创建生成器”。

考虑这段代码:

class Foo:SequenceType {
    var vals:[Int] = [1,2,3]
    func generate() -> Array<Int>.Generator {
        return vals.generate()
    }
}

let foo = Foo()
let seq = MySequenceOf(foo)
foo.vals = [4,5,6]
let result = Array(seq)

问题是:result应该是 [1,2,3][4,5,6] ?我的MySequenceOf和内置 SequenceOf结果是后者。我只是将行为与内置行为相匹配。

关于swift - 类型删除的通用包装器是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26832498/

相关文章:

ios - Swift 中的 RSA 公钥加密

ios - 我可以在单击按钮时以编程方式更改 Localizable.strings 文件而不重新启动应用程序吗

swift - Swift 中的高精度 float

c# - 使用动态关键字转换泛型类型是否会导致装箱?

java - Java中类型删除的异常(exception)是什么?

c# - 直接使用 Linq 表达式变量而不是 lambda 表达式时出错

Java 类型泛型作为 GSON 的参数

具有不同泛型参数的 C# 泛型返回类型

swift - 如何在 Swift 中停止/取消 playSoundFileNamed?

ios - 想要根据刷卡 ID 在主屏幕上显示完成的总百分比