在Swift中使用协议键入约束问题

时间:2014-10-17 07:47:20

标签: swift

我有一个协议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(&#34;无法转换表达式&#39;(($ T4,($ T4,$ T5) - &gt;($ T4,$ T5) - &gt; $ T3) - &gt;($ T4,($ T4,$ T5) - &gt; $ T3) - &gt; $ T3,(($ T4,$ T5) - &gt;($ T4,$ T5) - &gt; $ T3,$ T5) - &gt;(($ T4,$ T5) - &gt; $ T3,$ T5) - &gt; $ T3) - &gt; (($ T4,($ T4,$ T5) - &gt; $ T3) - &gt; $ T3,(($ T4,$ T5) - &gt; $ T3,$ T5) - &gt; $ T3) - &gt; $ T3&#39;键入&#39; AProtocol&#39;&#34;):

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
            }
        })
    }
}

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

2 个答案:

答案 0 :(得分:1)

你可以用

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

我不确定它是否是禁止您直接转换此数组的语言中的错误或某些约束。它可能是不可能的,因为数组是值类型。

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

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

答案 1 :(得分:1)

为了实现这一点,你必须:

  • 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],如果可能的话。< / p>

根据您尝试实现的目标,您可以通过将泛型类型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方法所期望的相同类型的元素。