【发布时间】:2021-01-29 16:52:41
【问题描述】:
想出一个准确的标题有点困难,所以我将用一个简单的例子来说明我的问题。我想创建一个协议,指定一个坚持者能够被转换成不同的类型:
protocol Transformable {
associatedtype TransformableTo
func transform() -> TransformableTo
}
然后为每种类型创建特定的协议:
protocol DoubleTransformable: Transformable where TransformableTo == Double {}
例如,如果我希望字符串能够转换为双精度,我会写:
extension String: DoubleTransformable {
func transform() -> Double {
return Double(self)
}
}
这很有效,直到我想让给定类型符合这些“特定”可转换合同中的更多:
protocol DecimalTransformable: Transformable where TransformableTo == Decimal {}
extension String: DecimalTransformable {
func transform() -> Decimal {
...
}
}
由于DecimalTransformable 的TransformableTo 类型与DoubleTransformable 的TransformableTo 类型冲突,编译器在上面的String 扩展上对我咆哮。这对我来说很有意义,但我没有看到解决方法。任何关于如何解决这个问题和/或完成相同事情的不同方向的建议将不胜感激。
编辑
添加更多关于用例的上下文以帮助解决 cmets 中的一些问题。这是实际代码的简化版本,所以这可能看起来有点奇怪,但我认为它明白了这一点。
我有两个结构,一个代表面向公众的模型,一个代表“支持”模型的数据。我不想将 PrivateModel 中的数据暴露给客户端,因此 PublicModel 充当 PrivateModel 和客户端之间的中间人。我要解决的问题是,有时 PrivateModel 属性的类型与我希望 PublicModel 的相应属性的类型不同(并且更改 PrivateModel 的类型是不可能的)。
struct PrivateModel {
var date: String { return "Jan. 1, 1970" }
}
struct PublicModel {
private let privateModel: PrivateModel
init(source: PrivateModel) {
self.privateModel = source
}
var date: Date {
return self.privateModel.date.transform()
}
}
注意公共模型中对transform 的调用。我的实际目标是拥有一个可以在任何类型对象上调用的单一转换方法,其中 transform 的通用返回类型由我所在的 getter 的属性类型推断。
【问题讨论】:
-
associatedtype = TransformableTo没有任何意义。你的意思是associatedtype TransformableTo -
正确 -- 已编辑
-
我认为这里的问题与多态性(方法重载)有关,仅在方法参数更改但返回值不更改时才有效,并且如果协议包含一个方法,则符合类型只能实现此方法的 一个 版本。我正在玩弄有两个关联类型“from”和“to”,并且还通过更改方法的签名而不是只有关联类型“to”但作为方法的参数,但我没有得到任何一个工作。
-
更进一步的 Joakim 的观点 -
Transformable协议指定一个符合的类型将为TransformableTo定义一个 concrete 类型 -Double或Decimal或任何其他类型 - 这就是transform将返回的内容。所以,不可能是不同的。遇到泛型和/或协议问题的最常见方法是,您首先尝试定义协议,而不是从特定案例开始,然后添加另一个案例,然后查看是否有协议甚至是有道理的。那么……你打算如何使用这种类型?那么,什么是需要协议的用例呢? -
恢复关联类型不是通用的。我同意 New Dev 关于需要使用协议的观点。这可以通过扩展 String 并创建一些通用方法来轻松解决