【问题标题】:Swift protocol generic as function return typeSwift 协议泛型作为函数返回类型
【发布时间】:2016-06-01 04:34:13
【问题描述】:

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

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

但是这段代码编译时报错:

  1. 无法专门化非泛型类型“P”
  2. 函数签名中未使用通用参数“T”

有什么方法可以用Swift实现类似的功能吗?

【问题讨论】:

  • 哪些行有错误?我想我知道#2 在哪里而不是 #1。
  • @TroyT 代码为func createC&lt;T&gt;() -&gt; P&lt;T&gt; {的行

标签: swift generics


【解决方案1】:

问题是您不能使用语法P&lt;T&gt;P 是一个协议,这意味着它不能被视为泛型类型 (Cannot specialize non-generic type 'P'),即使它可能具有给定的 associatedtype

事实上,因为它有一个associatedtype,你现在甚至不能直接使用协议类型本身——你只能将它用作一个通用约束。

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

class Factory {
    func createC<T>() -> C<T> {
        return C<T>()
    }
}

我不完全确定将返回类型设置为此处的协议会带来什么。大概您的示例只是您实际代码的简化,并且您希望能够返回符合P 的任意实例。在这种情况下,您可以使用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>())
    }
}

【讨论】:

【解决方案2】:

Swift 5.1 支持使用 Opaque 类型返回关联类型。使用 opaque 类型,您的代码可以成功构建。 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>()
}

【讨论】:

    猜你喜欢
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    相关资源
    最近更新 更多