无法推断通用参数 - 数组扩展

时间:2018-02-05 16:05:45

标签: ios swift

我有通用的方法来创建扩展协议FromResponse的对象。

extension FromResponse {
    static func object<T>(_ response: [String: Any]?) -> T? where T: FromResponse, T: NSObject {
        guard let response = response else { return nil }
        let obj: T = T()
        return obj
    }
}

所以每当我想从代码中的任何地方调用它时都没有问题。让我们说:

let myObject: MyObject? = MyObject.object(response)

工作完美。但有时我会从我的回复中获取对象数组,所以我也想要通用解析器:

static func objects<T>(_ response: [[String: Any]]?) -> [T]? where T: FromResponse, T: NSObject {
    guard let response = response else { return nil }
    var returnArray: [T] = [T]()
    for singleResponse in response {
        if let object: T = T.object(singleResponse) {
            returnArray.append(object)
        }
    }
    return returnArray
}

所以我期望从这个方法返回MyObject的数组,但实际上我在调用它时遇到了编译错误:

let myObjects: [MyObject]? = MyObject.objects(response)

它说:

  

通用参数&#39; T&#39;无法推断

嗯,我知道这是什么意思但我确实指定了类型,所以这个错误不应该发生。当我这样做时:

var typ: [MyObject] = [MyObject]()
for singleResponse in (response as? [[String: Any]])! {
    let pack: MyObject? = MyObject.object(singleResponse)
    typ.append(pack!)
 }

有效!

为什么呢?如何使用返回泛型对象数组的解析器?

1 个答案:

答案 0 :(得分:2)

我不确定为什么Swift说“通用参数&#39; T&#39;无法推断“,但我的猜测是它与数组协方差有关。

什么是协方差?考虑一下:

class Base { }
class Sub: Base { }
func f(_ array: [Base]) { }

您可以将[Sub]传递给f吗?在Swift中,你可以。由于SubBase的子类型,[Sub][Base]的子类型。 (这称为“协方差”。)因此,您可以在允许[Sub]的任何地方传递[Base]

f([Sub]())
// No errors.

您可以返回[Sub],其中[Base]是预期的:

func g() -> [Base] { return [Sub]() }
// No errors.

您可以将[Sub]分配给[Base]变量:

let bases: [Base] = [Sub]()
// No errors.

回到你的代码:

static func objects<T>(_ response: [[String: Any]]?) -> [T]? ...

let myObjects: [MyObject]? = MyObject.objects(response)

当然MyObject.objects(_:)必须返回一个可以视为[MyObject]?的类型。但是[MyObject]?的任何子类型也是可以接受的。类型没有严格约束。我想这就是斯威夫特不喜欢它的原因。

解决方法是使用您在Swift标准库中的许多地方看到的模式,明确告诉Swift您想要什么类型:

static func objects<T>(ofType type: T.Type, from response: [[String: Any]]?) -> [T]? ...
// Note that you might not actually have to use the `type` parameter
// in the method definition.

let myObjects = MyObject.objects(ofType: MyObject.self, from: response)

目前尚不清楚为什么这种方法完全在MyObject类。也许你应该在[[String: Any]]

上建立一个方法
extension Collection where Element == [String: Any] { 
    func objects<T>(ofType type: T.Type) -> [T]? ...
} 

let myObjects = response.objects(ofType: MyObject.self)