I'm trying to use a generic modular function within Combine, but I'm getting the error that generic could not be inferred.
func foo<T>(data: T) -> AnyPublisher<Bool, MyError> {
}
func bar<T>(data: T) -> AnyPublisher<String, MyError> {
Deferred { [weak self] () -> AnyPublisher<Bool, MyError> in
guard let foo = self?.foo else { // error here
return Fail(error: .someError)
.eraseToAnyPublisher()
}
return foo(data)
}
.eraseToAnyPublisher()
.flatMap { [weak self] (value) -> AnyPublisher<String, MyError> in
Future<String, MyError> { [weak self] promise in
// do something with the returned value
promise(.success("Success"))
}
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
enum MyError: Error {
case someError
}
I'm getting the error when I'm trying to unwrap a function using a guard statement. T
doesn't have constraints because it could be multiple disparate types like Data
or UIImage
which gets type checked within the foo
function.
CodePudding user response:
When you have a problem like this, simplify. We can reduce the phenomenon to a very simple case:
class MyClass {
func foo<T>(data: T) -> Void { }
func bar<T>(data: T) -> Void {
let foo = self.foo // error
}
}
Now, the first thing to realize is that you have two separate T placeholders. You say T with regard to foo
and with regard to bar
, but they have no relation to one another. We can rewrite more clearly:
class MyClass {
func foo<FooDataType>(data: FooDataType) -> Void { }
func bar<BarDataType>(data: BarDataType) -> Void {
let foo = self.foo // error: Generic parameter 'FooDataType' could not be inferred
}
}
Now it's clear what the problem is, because we know which placeholder the compiler is having trouble with. When you look at it that way, you realize that FooDataType is entirely confined to foo
. How would bar
know what type this is going to be?
If your idea is that they should be the same type, then say so. Make the class the generic, not the individual functions:
class MyClass<T> {
func foo(data: T) -> Void { }
func bar(data: T) -> Void {
let foo = self.foo // fine
}
}