类型擦除的通用包装器是如何实现的? [英] How is a type-erased generic wrapper implemented?

查看:100
本文介绍了类型擦除的通用包装器是如何实现的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我刚刚复制&粘贴 SequenceOf 的声明,将其重命名为 MySequenceOf ,并填写一些存根以获取:

  ///一个类型擦除序列。 
///
///使用
///相同的`Element`类型将操作转向任意的基础序列,隐藏底层
///序列的细节类型。
///
///另请参阅:`GeneratorOf< T>`。
struct MySequenceOf< T> :SequenceType {

///构造一个实例,其`generate()`方法转发给
///`makeUnderlyingGenerator`
init< G:GeneratorType其中T == T> ;(_ makeUnderlyingGenerator:() - > G){
fatalError(implement我)
}

///构造一个其generate()方法的实例转发给
///base。
init< S:SequenceType where T == T>(_ base:S){
fatalError(implement我)
}

///返回一个*发生器*在这个*序列*的元素上。
///
///复杂度:O(1)
func generate() - > GeneratorOf< T> {
fatalError(实施我)
}
}

我得到的编译器错误:两种类型都不指向泛型参数或关联类型。所以我假设Xcode生成的 SequenceOf 其中T == T 约束的声明真的意味着 其中G.Element == T ,它给了我下面的可编译结构:

  struct MySequenceOf< T> :SequenceType {

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

func generate() - > GeneratorOf< T> {
fatalError(实施我)
}
}

所以,现在很简单,我只需要从初始化程序挂到 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其中G.Element == T>(_ makeUnderlyingGenerator:() - > G){
self.maker = {返回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其中S.Generator.Element == T>(_ base:S){
_generate = {MyGeneratorOf(base.generate())}
}

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

struct MyGeneratorOf< T> :GeneratorType,SequenceType {

private让_next :() - > T'

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

init< G:GeneratorType其中G.元素== 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() - >价值
func methodB(arg:Value) - > Bool
}

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

init< B:ProtocolType其中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)}
}







是否有一个特殊原因,_generate是一个闭包而不是生成器本身?


首先,我认为,这是一个规范或语义问题。
$ b

不用说,不同之处在于何时创建生成器。

请考虑以下代码:

  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 产生后者。我只是将行为与内置行为进行了匹配。


I need to implement a type-erasing wrapper for my own structure, very similar to SequenceOf, GeneratorOf, etc. So I started by trying to just re-implement the standard SequenceOf myself.

I just copied & pasteed the the declaration for SequenceOf, renamed it to MySequenceOf, and filled in some stubs to get:

/// 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")
    }
}

I get the compiler error: "Neither type in same-type refers to a generic parameter or associated type". So I assume that the Xcode-generated declaration of SequenceOf's "where T == T" constraint really means "where G.Element == T", which gives me the following compilable struct:

struct MySequenceOf<T> : SequenceType {

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

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

So now, easy enough, I just need to hang on to makeUnderlyingGenerator from the initializer and invoke it from 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()
    }
}

but that gives me the error: "'G' is not convertible to 'GeneratorOf'"

It does compiles if I force a cast:

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()
    }
}

But then it crashes at runtime from the dynamic cast.

So how can type-erasure like this be implemented? It must be possible, because the Swift standard library does it a bunch (SequenceOf, GeneratorOf, SinkOf).

解决方案

Try:

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
    }
}

The basic strategy of implementing ProtocolOf<T> is, like this:

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) }
}


Added to answering @MartinR in comment.

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

First of all, I think, It's a matter of specification or semantics.

Needless to say, the difference is "when to create the generator".

Consider this code:

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)

The problem is: result should be [1,2,3] or [4,5,6]? My MySequenceOf and built-in SequenceOf results the latter. I just matched the behaviors with built-in one.

这篇关于类型擦除的通用包装器是如何实现的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆