【问题标题】:Unexpected compiler error when attempting to use generic type in closure尝试在闭包中使用泛型类型时出现意外的编译器错误
【发布时间】:2019-03-22 22:37:48
【问题描述】:

给定一个没有任何恐惧的协议:

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 类型。

我看到的是这个错误:

我的泛型知识很可能存在漏洞,我哪里错了?

【问题讨论】:

    标签: swift generics


    【解决方案1】:

    问题在于,在这种情况下,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) }
    

    所以这会将"" 传递给闭包。怎么会这样?

    所以你要么需要闭包句柄anyNonFunkyProtocol(我强烈怀疑这就是你的意思):

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

    或者您需要通过将T 设为关联类型来将weeProp 确定为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 真的只是这一要求,那么您还应该问一下它解决了什么问题而不是一个函数。当您可以直接使用 wee.funky 函数时,为什么还要传递 WeeStruct 及其所有协议包? FunkyProtocol 上有协议扩展吗?如果你不能针对 FunkyProtocol 编写通用算法,它可能不应该是一个协议。

    【讨论】:

    • 灯泡时刻!非常感谢,在这个特定的例子中你是对的,它不应该是一个协议,但它只是一个非常精炼的例子,试图让我解决我在一个项目中面临的问题。
    猜你喜欢
    • 1970-01-01
    • 2011-07-23
    • 2016-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多