【问题标题】:Why can this protocol "only be used as a generic constraint"?为什么这个协议“只能用作通用约束”?
【发布时间】:2014-07-12 01:56:34
【问题描述】:

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

protocol ProtocolWithAlias {
    typealias T
}

protocol AnotherProtocol {
    func someFunc() -> ProtocolWithAlias
}

但我收到错误: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。

谢谢!

【问题讨论】:

    标签: generics swift xcode6


    【解决方案1】:

    试试这个:

    func someFunc<T:ProtocolWithAlias>() -> T
    

    【讨论】:

    • 你会知道为什么会这样吗?这似乎是一个相当奇怪的语法,但也许这只是因为我习惯了 C# :)
    • 问题在于,如果您只指定协议,类型系统不知道为关联类型插入什么,因此您创建了一个通用函数,可以专门用于返回任何特定的具体符合协议的类型,而不仅仅是“协议”。编译器应该可以解决这个问题,但目前还不能。
    • 不错,但是如何将这个通用协议指定给类的实例变量?
    • @Dragouf 假设您有一个通用类型为“T”的协议“G”,并且您想将该协议作为变量添加到类“C”中。类“C”的声明为“class C”,实例变量的类型为“U”
    • @Zag 我假设“通用类型”是指“关联类型”。在这种情况下,C 类会出错:“Cannot use associated type 'T' outside it's protocol”。
    【解决方案2】:

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

    protocol ProtocolWithAlias {
        typealias T
    }
    
    protocol ProtocolConsumer {
        func consume<T: ProtocolWithAlias>(value: T)
    }
    
    protocol AnotherProtocol {
        func someFunc(consumer: ProtocolConsumer)
    }
    

    这个技巧被称为将函数转换为continuation passing style (CPS)。不幸的是,如果没有 CPSing,我找不到任何方法来实现这一点。我们正在寻找的类型系统功能是存在类型(this 线程有一个很好的解释),但我认为 Swift 还不支持它们。


    为什么另一个答案不正确?这个签名说明了什么:

    func someFunc<T:ProtocolWithAlias>() -> T
    

    这个函数可以为实现调用者选择的任何类型的ProtocolWithAlias返回一个类型T的值,但我们希望它由被调用者选择。

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

    class Uninhabited: ProtocolWithAlias {
        typealias T = Int
        init(nope: Uninhabited) {}
    }
    
    ...
    
    let impossible: Uninhabited = someFunc<Uninhabited>()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-15
      • 2020-04-18
      • 1970-01-01
      • 1970-01-01
      • 2016-08-16
      相关资源
      最近更新 更多