尝试在闭包中使用泛型时发生意外的编译器错误

时间:2019-03-22 14:21:00

标签: swift generics

给出没有任何功能的协议:

protocol NonFunkyProtocol {}

还有一个带有一些严重缺陷的协议:

protocol FunkyProtocol {
    func funky<T: NonFunkyProtocol>(_ closure: (T) -> Void)
}

然后给出此结构:

struct WeeStruct: FunkyProtocol {
    let weeProp: NonFunkyProtocol

    func funky<T>(_ closure: (T) -> Void) where T: NonFunkyProtocol {
        closure(weeProp)
    }
}

我希望它可以编译,因为closure中期望的参数类型为T,其中T符合NonFunkyProtocol,而weeProp的类型为NonFunkyProtocol。

相反,我看到此错误:

error

在我的仿制药知识中,我很有可能会出现一个漏洞,我在哪里出错?

1 个答案:

答案 0 :(得分:4)

问题在于,在这种情况下,T是“符合NonFunkyProtocol的某种类型”。 weeProp也是“符合NonFunkyProtocol的事物”,但没有任何内容表明weeProp的类型为T

请考虑以下情况:

extension Int: NonFunkyProtocol {}
extension String: NonFunkyProtocol {}

Int和String都符合。

现在我用一个字符串构造一个WeeStruct:

let wee = WeeStruct(weeProp: "")

然后我使用需要一个Int的函数来调用funky(由于Int是一致的类型,它可以是T):

wee.funky { (int: Int) -> Void in print(int + 1) }

因此这会将""传递给闭包。那怎么办?

所以您要么需要关闭句柄 any NonFunkyProtocol(我强烈怀疑这是您的意思):

func funky(_ closure: (NonFunkyProtocol) -> Void)

或者您需要通过将weeProp设置为关联类型来将T固定为T

protocol FunkyProtocol {
    associatedtype T: NonFunkyProtocol
    func funky(_ closure: (T) -> Void)
}

struct WeeStruct<T:NonFunkyProtocol>: FunkyProtocol {
    let weeProp: T

    func funky(_ closure: (T) -> Void) {
        closure(weeProp)
    }
}

不过,在添加关联类型之前,我会非常小心。这完全改变了FunkyProtocol的性质。

如果FunkyProtocol确实只是这一要求,那么您还应该问它要解决的是什么,而不仅仅是一个功能。当您可以直接使用WeeStruct函数时,为什么要随身携带wee.funky的所有协议包呢? FunkyProtocol上有协议扩展吗?如果您不能针对FunkyProtocol编写通用算法,则可能不应该是协议。