为什么这个协议"只能用作通用约束"?

Mat*_*Sot 27 generics swift xcode6

我试图在Swift中执行以下操作:

protocol ProtocolWithAlias {
    typealias T
}

protocol AnotherProtocol {
    func someFunc() -> ProtocolWithAlias
}
Run Code Online (Sandbox Code Playgroud)

但我得到错误:Protocol 'ProtocolWithAlias' can only be used as a generic constraint because it has Self or associated type requirements.

可以这样做吗?错误消息(或至少" only be used as a generic constraint"部分)对我来说似乎没有多大意义.

我正在使用最新的Xcode 6 beta 3.

谢谢!

Cat*_*Man 23

试试这个:

func someFunc<T:ProtocolWithAlias>() -> T
Run Code Online (Sandbox Code Playgroud)

  • 问题是,如果您只是指定协议,类型系统不知道要为相关类型插入什么,那么您可以创建一个通用函数,可以专门返回符合协议的任何特定具体类型,但是不只是"协议".编译器应该能够解决这个问题,但目前还不能. (8认同)
  • 很好,但如何将此通用协议指定为类的实例变量? (2认同)

小智 13

可以通过反转控件来实现它:不是从someFunc返回一个值,而是传递一个消费者,它可以接受任何实现ProtocolWithAlias的类型并对它做一些事情.

protocol ProtocolWithAlias {
    typealias T
}

protocol ProtocolConsumer {
    func consume<T: ProtocolWithAlias>(value: T)
}

protocol AnotherProtocol {
    func someFunc(consumer: ProtocolConsumer)
}
Run Code Online (Sandbox Code Playgroud)

这个技巧被称为将函数转换为连续传递样式(CPS).不幸的是,如果没有CPSing,我找不到任何实现方法.我们正在寻找的类型系统特性是存在类型(这个线程有一个很好的解释),但我认为Swift不支持它们(尚未).


为什么另一个答案不正确?这个签名告诉我们:

func someFunc<T:ProtocolWithAlias>() -> T
Run Code Online (Sandbox Code Playgroud)

是这个函数可以返回类型T的值的任何类型的实施ProtocolWithAlias来电者选择,但我们希望它被选择被叫方.

甚至不可能写出这个函数的合理实现.让我假装我有someFunc的实现:我可以创建一个实现ProtocolWithAlias的新类,并请求someFunc以某种方式创建此类的实例:

class Uninhabited: ProtocolWithAlias {
    typealias T = Int
    init(nope: Uninhabited) {}
}

...

let impossible: Uninhabited = someFunc<Uninhabited>()
Run Code Online (Sandbox Code Playgroud)