简体   繁体   中英

Swift protocol generic as function return type

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:

  1. Cannot specialize non-generic type 'P'
  2. Generic parameter 'T' is not used in function signature

Is there any way to achieve similar function with Swift?

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>()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM