Rah*_*iya 7 generics swift swift2
有一个协议Printable和一个来自第三方的结构打印机.
protocol Printable {}
struct Printer {
static func print<T>(object: T) -> String {
return "T"
}
static func print<T: Printable>(object: T) -> String {
return "Printable"
}
}
Run Code Online (Sandbox Code Playgroud)
现在我正在制作一个通用的
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
Run Code Online (Sandbox Code Playgroud)
和两个结构
struct Obj {}
struct PrintableObj: Printable {}
var obj = Generic(args: Obj())
var printableObj = Generic(args: PrintableObj())
Run Code Online (Sandbox Code Playgroud)
当我在它们上面调用显示功能时.
obj.display()
Run Code Online (Sandbox Code Playgroud)
显示T.
printableObj.display()
Run Code Online (Sandbox Code Playgroud)
显示T但我希望它打印"可打印"
我能想到的一个解决方案是拥有两种不同的泛型
struct Generic<T>
struct PrintableGeneric<T: Printable>
Run Code Online (Sandbox Code Playgroud)
是否有任何其他解决方案,而无需更改Printable协议和Printer结构.
是的。但答案有点奇怪。第一部分很有道理;第二部分非常奇怪。让我们来看看它。
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
Run Code Online (Sandbox Code Playgroud)
选择正确的重载print是在编译时而不是运行时决定的。这是最让人困惑的事情。他们希望像 JavaScript 一样对待 Swift,一切都是动态的。Swift 喜欢静态,因为这样它可以确保你的类型是正确的,并且可以进行大量优化(并且 Swift喜欢进行编译器优化)。那么,编译时,什么类型args?嗯,是的T。T已知是Printable?不它不是。所以它使用非Printable版本。
但是当 Swift 专门Generic使用时PrintableObj,它难道不知道它是 吗Printable?display编译器当时不能创建不同的版本吗?是的,如果我们在编译时知道该函数将存在的每个调用者,并且它们都不会被扩展Printable(这可能发生在完全不同的模块中)。如果不创建大量奇怪的极端情况(例如,内部事物的行为与公共事物不同),并且不强迫 Swift 主动生成display未来调用者可能需要的每个可能版本,就很难解决这个问题。Swift 可能会及时改进,但我认为这是一个难题。(Swift 已经遭受了一些性能下降,因此公共泛型可以在不访问原始源代码的情况下进行专门化。这将使该问题变得更加复杂。)
好的,我们明白了。T不是Printable。但是,如果我们有一个在编译时明确知道的类型并且存在于该函数内,该怎么办?Printable那样行得通吗?
func display() {
if let p = args as? Printable {
print(Printer.print(p))
} else {
print(Printer.print(args))
}
}
Run Code Online (Sandbox Code Playgroud)
哦,如此接近……但不完全是。这几乎有效。实际上,它if-let完全按照您想要的方式执行。p被分配。它是Printable。但它仍然调用非 Printable 函数。?!?!?!?!
我个人认为 Swift 目前存在这个问题,并且非常希望它能够得到修复。它甚至可能是一个错误。问题是Printable本身不符合Printable。是的,我也不明白,但你明白了。因此,我们需要制作一些符合要求的东西才能获得Printable正确的过载。像往常一样,使用橡皮擦来救援。
struct AnyPrintable: Printable {
let value: Printable
}
struct Generic<T> {
var args: T
func display() {
if let p = args as? Printable {
print(Printer.print(AnyPrintable(value: p)))
} else {
print(Printer.print(args))
}
}
}
Run Code Online (Sandbox Code Playgroud)
这将按照您想要的方式打印。(假设Printable需要一些方法,您只需将这些方法添加到AnyPrintable类型橡皮擦中即可。)
当然,正确的答案是不要在Printer. 它实在是太混乱和脆弱了。看起来很好看,但是总是会爆炸。
| 归档时间: |
|
| 查看次数: |
475 次 |
| 最近记录: |