第三方有一个Printable协议和一个struct Printer。
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但我想要打印&#34;可打印&#34;
我能想到的一个解决方案是拥有两种不同的泛型
struct Generic<T>
struct PrintableGeneric<T: Printable>
在没有更改Printable协议和Printer结构的情况下是否还有其他解决方案。
答案 0 :(得分:2)
static func print<T>(object: T) -> String {
if object is Printable {
return "Printable"
} else {
return "T"
}
}
答案 1 :(得分:1)
在我看来,你唯一的选择就是在&#34; print()&#34;中使用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"
}
答案 2 :(得分:1)
是。但答案有点奇怪。第一部分有一定的意义;第二部分是完全奇怪的。让我们来看看吧。
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
为print
选择正确的重载是在编译时决定的,而不是运行时。这是最让人困惑的事情。他们希望将Swift视为JavaScript,其中一切都是动态的。 Swift喜欢静态,因为它可以确保你的类型是正确的,它可以做很多优化(和Swift 喜欢进行编译器优化)。那么,编译时间,args
是什么类型的?好吧,它是T
。已知T
为Printable
?不它不是。所以它使用非{{1}}版本。
但是当Swift使用Printable
专攻Generic
时,它是否知道那时它是PrintableObj
?编译器无法在此时创建Printable
的不同版本吗?是的,如果我们在编译时知道这个函数将存在的每个调用者,并且它们都不会被扩展为display
(这可能发生在一个完全不同的模块中)。如果不创建许多奇怪的角落情况(例如内部事物的行为与公共事物不同),并且不强制Swift主动生成某些未来调用者可能需要的Printable
的每个可能版本,就很难解决这个问题。斯威夫特可能会及时改进,但我认为这是一个难题。 (Swift已经遭受了一些性能下降,因此公共泛型可以在不访问原始源代码的情况下进行专业化。这会使问题变得更加复杂。)
好的,我们明白了。 display
不是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
的内容,以便获得正确的重载。像往常一样,type erasers来救援。
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
中以这种方式使用泛型重载。这太令人困惑和脆弱了。它看起来很漂亮,但它一直在爆炸。