Общий параметр T не может быть выведен. Фабричные методы

Может кто-нибудь объяснить мне, почему это не сработает?

У меня есть класс с методами фабрики, как это:

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

    }

Нету...

Общий параметр T не может быть выведен

Подождите, я могу ясно сделать вывод, метод возвращает NetworkTask<NSData>, так что T является NSData.

Хорошо... тогда, может быть, так?

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

}

Нету...

Невозможно вызвать 'dataResponseTaskWithRequest' со списком аргументов типа '(URLRequest, (_) -> _)'

Хорошо, возможно, другой метод:

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

}

Нету...

Невозможно преобразовать значение типа "(NetworkResponse) -> ()" в ожидаемый тип аргумента "NetworkResponse<_> -> Void"

Я, должно быть, явно что-то здесь упускаю, потому что компилятор не может иметь так много ошибок. У кого-нибудь есть подсказка?

1 ответ

Решение

NetworkTask<T> это тип, а не NetworkTask, То есть параметр T находится в классе, и все, что вы делаете с этим классом, а также для доступа к его методам класса, требует описания этого типа.

Хотя T не включен в объявление метода, которое выдает ошибку компилятора, класс отсутствует NetworkTask это будет содержать все методы класса, где параметр типа не включен - представьте вместо этого, что метод на всех классах 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или должны ли они иметь что-то еще в качестве приемника (или действительно ли они должны быть свободными функциями?).

Другие вопросы по тегам