无法推断出通用参数T.工厂方法

时间:2016-05-05 22:03:29

标签: swift generics

有人可以向我解释为什么这不起作用吗?

我有一个类,有这样的工厂方法:

public class NetworkTask<T> {

    var request: URLRequest

    var completionHandler: NetworkResponse<T> -> Void

    init(request: URLRequest, completionHandler: NetworkResponse<T> -> Void) {

        self.request = request
        self.completionHandler = completionHandler
    }

    static func dataResponseTaskWithRequest(request: URLRequest, completionHandler: NetworkResponse<NSData> -> Void) -> NetworkTask<NSData> {

        return NetworkTask<NSData>(request: request, completionHandler: completionHandler)
    }

    static func mappedObjectResponseTaskWithRequest<MappedType>(request: URLRequest, completionHandler: NetworkResponse<MappedType> -> Void) -> NetworkTask<MappedType> {

        return NetworkTask<MappedType>(request: request, completionHandler: completionHandler)
    }
}

然后,在愉快地知道它编译后,我去创建一个这样的任务:

let task = NetworkTask.dataResponseTaskWithRequest(URLRequest()) { (response) in

    }

没有......

  

无法推断通用参数

等等,我可以清楚地推断出来,该方法返回NetworkTask<NSData>,所以T是NSData。

好的......那么,也许是这样的?

let task: NetworkTask<NSData> = NetworkTask.dataResponseTaskWithRequest(URLRequest()) { (response) in

}

没有......

  

无法使用类型为'(URLRequest,(_) - &gt; _)'的参数列表调用'dataResponseTaskWithRequest'

好的,也许是另一种方法:

let task = NetworkTask.mappedObjectResponseTaskWithRequest(URLRequest()) { (response: NetworkResponse<String>) in

}

...都能跟得上

  

无法转换类型的值'(NetworkResponse) - &gt; ()'到了预期   参数类型'NetworkResponse&lt; _&gt; - &GT;无效“

我必须在这里明显遗漏一些东西,因为编译器不会有这么多错误。有人有任何线索吗?

1 个答案:

答案 0 :(得分:4)

NetworkTask<T>是类型,而不是NetworkTask。也就是说,参数T在类上,并且您对该类执行的所有操作(也是访问其类方法)都需要描述该类型。

即使T未包含在为您提供编译器错误的方法声明中,也没有类NetworkTask包含所有不包含type参数的类方法 - 想象一下相反,该方法适用于NetworkTask<T>的任何值的所有类T。这类似于C ++,其中对应的甚至称为“模板”,这意味着具有泛型类型参数的类声明用作模板来逐字编译不同的类。这与例如Java不同,其中泛型语法只是带有类型擦除的编译时糖(你确实可以调用类方法 - 在这种情况下只存在一个类)。

以下是演示此内容的最小示例:

class A<T> {
    class func foo() {
    }

    class func bar(t:T) -> Void {
    }
}

class B {}

A.foo() // this gives an error because the type cannot be inferred.

A.bar(1) // this works fine without compiler errors as the integer literal type can be inferred there.

在上面的示例中,A可以通过以下方式调用:

A<IntegerLiteralType>.foo()

您应该考虑这种情况下的方法是否属于具有该类型参数T的类,或者它们是否应该将其他东西作为接收者(或者它们是否应该是自由函数?)。