【问题标题】:Type constraint issue with protocol in SwiftSwift 中协议的类型约束问题
【发布时间】:2014-10-17 07:47:19
【问题描述】:

我有一个协议AProtocol,它有一些数据结构和一个协议BProtocol,它有一个接受符合AProtocol 的参数的操作。代码如下:

protocol AProtocol {
    // data
}

protocol BProtocol {
    func action<T: AProtocol>(completionHandle: (Bool, [T]?) -> ())
}

当我实现这些协议时——结构符合AProtocol,类符合BProtocol,我找不到满足编译器的方法。

struct AStruct: AProtocol {

}

class BClass: BProtocol {
    var structs = [AStruct]()
    func action<T : AProtocol>(completionHandle: (Bool, [T]?) -> ()) {
        completionHandle(true, self.structs) // Compile error: "'AStruct' is not identical to 'T'"
    }
}

更新:

我尝试使用类型转换,但未能调用 action 并出现另一个错误(“无法转换表达式的类型 '(($T4, ($T4, $T5) -> ($T4, $T5) - > $T3) -> ($T4, ($T4, $T5) -> $T3) -> $T3, (($T4, $T5) -> ($T4, $T5) -> $T3, $ T5) -> (($T4, $T5) -> $T3, $T5) -> $T3) -> (($T4, ($T4, $T5) -> $T3) -> $T3, ( ($T4, $T5) -> $T3, $T5) -> $T3) -> $T3' 输入 'AProtocol'"):

class BClass: BProtocol {
    var structs = [AStruct]()
    func action<T : AProtocol>(completionHandle: (Bool, [T]?) -> ()) {
        completionHandle(true, self.structs.map({$0 as T})) // Now the compile error has gone
    }

    func testAction() {
        self.action({ // Compile error: "Cannot convert the expression's type..."
            (boolValue, arrayOfStructs) in
            if boolValue {
                // Do something
            }
        })
    }
}

我想知道为什么我错了以及如何解决问题。谢谢!

【问题讨论】:

    标签: swift


    【解决方案1】:

    你可以解决它

    completionHandle(true, self.structs.map { $0 as T })
    

    我不确定它是一个错误还是语言中的某些限制,禁止您直接转换此数组。这可能是不可能的,因为数组是值类型。

    对于您更新的问题: 您为操作方法指定了泛型类型,因此编译器无法从上下文中获取类型。您必须明确设置它:

    var bClass = BClass()
    bClass.action { (boolValue, arrayOfAProtocol: [AProtocol]?) in
        if boolValue {
            // Do something
        }
    }
    

    【讨论】:

    • 谢谢!它确实使编译器平静下来。但是当我尝试调用 action 方法时,又出现了另一个错误,这似乎与类型转换有关,如我更新的问题所示。
    • 还有一个小问题:bClass.action { (boolValue, arrayOfAProtocol: [AProtocol]?)应该是bClass.action { (boolValue, arrayOfAProtocol: [AStruct]?)
    【解决方案2】:

    为了让它发挥作用,你必须:

    • structs 类型从[AStruct] 更改为[AProtocol]
    • action 方法中,将self.structs 显式转换为[T]

    代码:

    class BClass: BProtocol {
        var structs = [AProtocol]()
        func action<T : AProtocol>(completionHandle: (Bool, [T]?) -> ()) {
            completionHandle(true,  self.structs as? [T])
        }
    }
    

    原因是action 方法期望任何类型 实现AProtocol。通过使用self.structs,您将强制它使用AStruct

    让我举个例子。考虑你有这个结构:

    struct BStruct: AProtocol {}
    

    它实现了AProtocol,因此根据方法定义,您应该能够使用它作为泛型类型调用action。但是BStruct 不是AStruct(尽管它们实现了相同的协议),所以编译器不知道如何将[AStruct] 转换为[BStruct],如果这可能的话。

    根据您要实现的目标,您可以稍微更改您的协议,将泛型类型 T 从方法移动到协议/类级别:

    protocol BProtocol {
        typealias DataType
        func action(completionHandle: (Bool, [DataType]?) -> ())
    }
    
    class BClass<T: AProtocol>: BProtocol {
        typealias DataType = T
    
        var structs = [T]()
        func action(completionHandle: (Bool, [T]?) -> ()) {
            completionHandle(true, self.structs)
        }
    }
    

    这确保structs 包含action 方法所期望的相同类型的元素。

    【讨论】:

    • 非常感谢!实际上,在提出问题之前,我已经使用了您发布的第二个解决方案。但是,由于我使用AProtocol 作为接口数据结构,我想对T 类型进行约束,以确保一切都与AProtocol 通信。所以我尝试了你的第一个解决方案,它就像一个魅力!如果我可以同时标记您的答案,我会将您的答案标记为已接受。我投票赞成。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    • 1970-01-01
    相关资源
    最近更新 更多