Общий параметр 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
или должны ли они иметь что-то еще в качестве приемника (или действительно ли они должны быть свободными функциями?).