I want to use generic protocol type as a function return type like this:
protocol P {
associatedtype T
func get() -> T?
func set(v: T)
}
class C<T>: P {
private var v: T?
func get() -> T? {
return v
}
func set(v: T) {
self.v = v
}
}
class Factory {
func createC<T>() -> P<T> {
return C<T>()
}
}
But this code compile with errors complained:
Is there any way to achieve similar function with Swift?
Using a protocol type as the return type for a function gives you the flexibility to return any type that conforms to the protocol. However, the cost of that flexibility is that some operations aren't possible on the returned values.
An associated type gives a placeholder name to a type that's used as part of the protocol. The actual type to use for that associated type isn't specified until the protocol is adopted. Associated types are specified with the associatedtype keyword.
The problem is you cannot use the syntax P<T>
. P
is a protocol, meaning it can't be treated as a generic type (Cannot specialize non-generic type 'P'
), even though it may have a given associatedtype
.
In fact, because it has an associatedtype
, you now can't even use the protocol type itself directly – you can only use it as a generic constraint.
One solution to your problem is to simply change your function signature to createC<T>() -> C<T>
, as that's exactly what it returns.
class Factory {
func createC<T>() -> C<T> {
return C<T>()
}
}
I'm not entirely sure what you would gain from having the return type be a protocol here. Presumably your example is just a simplification of your actual code and you want to be able to return an arbitrary instance that conforms to P
. In that case, you could use type erasure:
class AnyP<T> : P {
private let _get : () -> T?
private let _set : (T) -> ()
init<U:P where U.T == T>(_ base:U) {
_get = base.get
_set = base.set
}
func get() -> T? {return _get()}
func set(v: T) {_set(v)}
}
class Factory {
func createC<T>() -> AnyP<T> {
return AnyP(C<T>())
}
}
Swift 5.1 supports returning associated types using Opaque type. Using opaque type, your code builds successfully. Ref
protocol P {
associatedtype T
func get() -> T?
func set(v: T)
}
class C<T>: P {
private var v: T?
func get() -> T? {
return v
}
func set(v: T) {
self.v = v
}
}
class Factory {
func createC<T>() -> some P {
return C<T>()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With