Swift协议泛型为函数返回类型

ufo*_*sky 9 generics swift

我想使用通用协议类型作为函数返回类型,如下所示:

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>()
  }
}
Run Code Online (Sandbox Code Playgroud)

但是这个代码编译错误抱怨:

  1. 不能专门化非泛型类型'P'
  2. 函数签名中不使用通用参数"T"

有没有办法用Swift实现类似的功能?

Ham*_*ish 6

问题是您不能使用语法P<T>P是一个协议,意味着Cannot specialize non-generic type 'P'即使它可能具有给定,也不能将其视为通用类型()associatedtype

实际上,由于它具有associatedtype,您现在甚至不能直接使用协议类型本身–您只能将其用作一般约束。

解决问题的一种方法是将函数签名简单地更改为createC<T>() -> C<T>,因为这正是它返回的内容。

class Factory {
    func createC<T>() -> C<T> {
        return C<T>()
    }
}
Run Code Online (Sandbox Code Playgroud)

我不确定要从返回类型中获取协议将为您带来什么好处。假设您的示例只是实际代码的简化,并且您希望能够返回符合的任意实例P。在这种情况下,您可以使用类型擦除

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)}
}
Run Code Online (Sandbox Code Playgroud)

class Factory {
    func createC<T>() -> AnyP<T> {
        return AnyP(C<T>())
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

Swift 5.1 支持使用 Opaque 类型返回关联类型。使用 opaque 类型,您的代码构建成功。参考

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>()
}
Run Code Online (Sandbox Code Playgroud)