通用方法重写不在swift中工作
有一个来自第三方的协议Printable和一个结构打印机。
protocol Printable {}
struct Printer {
static func print<T>(object: T) -> String {
return "T"
}
static func print<T: Printable>(object: T) -> String {
return "Printable"
}
}
现在我正在制作一个通用的
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
和两个结构
struct Obj {}
struct PrintableObj: Printable {}
var obj = Generic(args: Obj())
var printableObj = Generic(args: PrintableObj())
当我在他们两个上调用显示功能时。
obj.display()
显示T
printableObj.display()
显示T但我希望它打印“可打印”
我能想到的一种解决方案是有两种不同的泛型
struct Generic<T>
struct PrintableGeneric<T: Printable>
是否有其他解决方案,而不更改Printable协议和打印机结构。
是。 但答案有点奇怪。 第一部分有一定的道理; 第二部分是完全怪异的。 我们来看看它。
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
选择print
的正确重载是在编译时决定的,而不是运行时决定的。 这是最让人混淆的东西。 他们希望像JavaScript那样处理Swift,其中一切都是动态的。 Swift喜欢静态,因为它可以确保你的类型是正确的,它可以做很多优化(Swift喜欢编译器优化)。 那么,编译时间, args
是什么类型? 那么,这是T
T
是否已知可Printable
? 不它不是。 所以它使用非Printable
版本。
但是,当Swift使用PrintableObj
专门化Generic
时,它不知道它是Printable
吗? 编译器能否在此时创建不同版本的display
? 是的,如果我们知道在编译时每个调用者都会存在这个函数,并且他们都不会被扩展为Printable
(这可能发生在一个完全不同的模块中)。 如果不创建很多奇怪的角落案例(例如,内部事物的行为与公共事物不同),并且不强制Swift主动生成未来呼叫者可能需要的每种可能的display
版本,都很难解决这个问题。 斯威夫特可能会及时改善,但我认为这是一个难题。 (Swift已经遭受了一些性能下降,所以公共泛型可以专门化,而无需访问原始源代码,这会使问题变得更加复杂。)
好的,所以我们明白了。 T
不是Printable
。 但是如果我们有一个明确的Printable
类型,那么我们在编译时就知道并且存在于这个函数中呢? 那么它会起作用吗?
func display() {
if let p = args as? Printable {
print(Printer.print(p))
} else {
print(Printer.print(args))
}
}
哦,那么近......但不完全。 这几乎可行。 if-let
实际上完全是你想要的。 p
被分配。 它是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))
}
}
}
这将打印你想要的方式。 (假设Printable
需要一些方法,您只需将这些方法添加到AnyPrintable
类型橡皮擦。)
当然,正确的答案并不是在Printer
以这种方式使用泛型重载。 这只是太混乱和脆弱的方式。 它看起来很不错,但它一直在爆炸。
static func print<T>(object: T) -> String {
if object is Printable {
return "Printable"
} else {
return "T"
}
}
在我看来,唯一的选择是 - 在“print()”函数中使用if-else进行类型转换
static func print<T>(object: T) -> String {
if let _ = object as? Printable {
return "Printable"
}
return "T"
}
或非通用变体
static func print(object: Any) -> String {
if let _ = object as? Printable {
return "Printable"
}
return "T"
}
链接地址: http://www.djcxy.com/p/90423.html