斯威夫特广义存在

时间:2016-09-13 11:52:16

标签: generics delegates swift3

除了冗余的介绍之外,我想要有这样的东西:

let collection : Any<Sequence where .Iterator.Element == String> = ...

let collection : Sequence<where .Iterator.Element == String> = ...

这被称为&#34;广义存在&#34;在Apple's Generics Manifesto。 (我认为)我真的需要这个用于许多用例和这个:

  

协议&#39; P&#39;只能用作通用约束因为   它有自我或相关的类型要求。

制作&#34;第一个面向协议的语言&#34;对我来说很难理解。缺乏这一点使我与Swift的类型系统作斗争并创造了不利的通用&#34;抽象&#34;应该有associatedtype协议的类。

这是一个最让我感到满意的例子,代表一个通用类:

protocol GenericClassDelegate : class {
    associatedtype ItemType
    func didDoThat(who : GenericClass<ItemType>) 
}

class GenericClass<T> {
    weak var delegate : GenericClassDelegate<where .ItemType == T>? // can't do that

    func notify() {
        delegate?.didDoThat(who: self)
    }
}

虽然我可以描述GenericClassDelegate协议,但我(目前在Swift 3中)不能拥有该类型的变量或常量(或任何符合限制的类型)。

不要将此问题与How to use generic protocol as a variable typeSwift delegate protocol for generic class混淆,因为我的问题是:

  1. 目前是否有任何关于将广义存在引入Swift的提议或讨论,计划是什么?如果不是,我该如何参与并影响这个?
  2. 如果以这种方式设计Swift(使用Associated Types,但没有Generalized Existentials),也许它意味着一些架构转变。我期望用?
  3. 替换委托模式

    P.S。当你在封闭中捕获代表的功能时,不要建议使用类型擦除的thunk,这是非常错误和误导,我甚至称之为拐杖。

    无意中发现了另一种解决方案,但我对此并不满意:

    protocol GenericClassDelegate : class {
        associatedtype ItemType
        func didDoThat(who : GenericClass<ItemType, Self>)
    }
    
    class GenericClass<T, Delegate : GenericClassDelegate> where Delegate.ItemType == T {
        weak var delegate : Delegate?
    
        func notify() {
            delegate?.didDoThat(who: self)
        }
    
        init(_ delegate : Delegate?) {
            self.delegate = delegate
        }
    }
    
    // Delegates must be final classes, otherwise it does not compile
    // because I used Self in GenericClassDelegate
    final class GenericClassDelegateImp<T> : GenericClassDelegate {
        typealias ItemType = T
        func didDoThat(who: GenericClass<T, GenericClassDelegateImp>) {
            print(who)
        }
    }
    
    // Usage:
    var delegate = GenericClassDelegateImp<Int>()
    var genericClass = GenericClass<Int, GenericClassDelegateImp<Int>>(delegate)
    

2 个答案:

答案 0 :(得分:4)

  

目前是否有关于将广义存在引入Swift的任何提案或讨论,计划是什么?如果不是,我该如何参与并对此产生影响?

这是一个常见的功能,并且已经有快速进化的初步设计工作。但此时,核心团队和社区正在关注影响功能的ABI稳定性,或Lattner定义为&#34; Swift 4 Phase 1&#34;。

第2阶段开始时你肯定会听到更多关于它的信息。鉴于其受欢迎程度,预计它将成为Swift 4的一部分。

  

如果以这种方式设计Swift(使用Associated Types,但没有Generalized Existentials),也许它意味着一些架构转变。我期望用?

替换委托模式

您可以使用类型擦除的包装器作为传递解决方案。通常,它利用动态分派和类的继承来擦除类型。

protocol Fancy {
    associatedtype Value
    var value: Value
}

struct FancyMatter<Value> {
    let value: Value
}

class AnyFancyBoxBase<P: FancyProtocol>: AnyFancyBox<P.Value> {
    let base: P
    override var value: P.Value { return base.value }
    init(_ base: P) { self.base = base }
}

class AnyFancyBox<Value> {
    var value: Value { fatalError() }
}

var box: AnyFancyBox<Int> = AnyFancyBoxBase(FancyMatter(1))

您可以查看how the Standard Library implements type-erased wrappers

答案 1 :(得分:0)

该代码不正确。刚编译的正确代码是:


protocol Fancy {
    associatedtype Value
    var value: Value {get set}
}


struct FancyMatter<Value>: Fancy  {
    var value: Value
}


class AnyFancyBoxBase<P: Fancy>: AnyFancyBox<P.Value> {
    let base: P
    override var value: P.Value {return base.value }
    init(_ base: P) { self.base = base }
}


class AnyFancyBox<Value> {
    var value: Value {fatalError() }
}


var box: AnyFancyBox<Int> = AnyFancyBoxBase(FancyMatter(value: 1))

// prove it out
print (AnyFancyBoxBase(FancyMatter(value: 1)).value)
print (box.value)