通用方法重写不在swift中工作 [英] Generic method override not working in swift
问题描述
协议Printable {}
struct Printer {
static func print< T>(object:T) - >字符串{
returnT
}
static func print< T:Printable>(object:T) - >字符串{
return可打印
}
}
现在我正在制作一个通用的
struct Generic< T> {
var args:T
func display(){
print(Printer.print(args))
}
$ / code>
和两个结构
<$ p $ obj())
var printableObj = Generic(args:PrintableObj){$ p $ {code $} ())
当我调用它们的显示函数时。
obj.display()
显示T
printableObj.display()
显示T但我希望它打印可打印
我可以想到的一个解决方案有两种不同的泛型
struct Generic< T>
struct PrintableGeneric< T:Printable>
是否有其他解决方案,而不更改Printable协议和Printer结构。 b
是的。但答案有点奇怪。第一部分有一定的道理;第二部分是完全怪异的。我们来看看它。
struct Generic< T> {
var args:T
func display(){
print(Printer.print(args))
}
}
选择 print
的正确重载是在编译时决定的,而不是运行时决定的。这是最让人混淆的东西。他们希望像JavaScript那样处理Swift,其中一切都是动态的。 Swift喜欢静态,因为它可以确保你的类型是正确的,并且它可以做很多优化(并且Swift loves 做编译器优化)。所以,编译时,什么类型是 args
?那么,它是 T
。已知 T
是可打印
?不它不是。所以它使用了非 Printable
版本。
但是当Swift专注于 好吧,那么我们明白了。 哦,太近了......但不完全。这几乎起作用。 这个地方我个人认为Swift目前刚刚破解,希望能够修复。它甚至可能是一个错误。问题是 这将以您想要的方式打印出来。 (假设 当然,正确的答案不是在 There is a protocol Printable and a struct Printer from a 3rd Party. Now i am making a generic and two structs When i call the display functions on both of them. displays T displays T but i want it to print "Printable" One solution i can think of is having two different generics Is there any other solution without changing the Printable protocol and Printer struct. Yes. But the answer is a bit weird. The first part makes a decent amount of sense; the second part is just totally weird. Let's walk through it. The correct overload to choose for But when Swift specializes OK, so we get that. Oh so close... but not quite. This almost works. The This is a place I personally think that Swift is just currently broken and have high hopes it will be fixed. It might even be a bug. The problem is that And this will print the way you wanted. (On the assumption that Of course the right answer is not to use generic overloads this way in 这篇关于通用方法重写不在swift中工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! Generic
使用
PrintableObj
,难道它不知道它是 Printable
?编译器能否在这一点上创建不同版本的 display ?是的,如果我们知道在编译时每个调用者都会存在这个函数,并且他们都不会被扩展为
Printable
(这可能会发生在一个完全不同的模块)。如果不创建很多奇怪的角落案例(例如内部事物的行为与公共事物不同),并且不强制Swift主动生成 display 的所有可能版本,这可能是一些未来的呼叫者所需要的。斯威夫特可能会及时改善,但我认为这是一个难题。 (Swift已经遭受了一些性能下降,所以公共泛型可以在没有原始源代码的情况下被专门化,这会让问题变得更加复杂。)
T
不是可打印
。但是如果我们有一个 > Printable 的类型,那么我们在编译时知道并且存在于这个函数中呢?那么它会起作用吗?
func display(){
if let p = args as? Printable {
print(Printer.print(p))
} else {
print(Printer.print(args))
}
}
if-let
实际上完全符合你的要求。 p
被赋值。它是可打印
。但它仍然称为非打印功能。
Printable
本身不符合 Printable
。是的,我也不明白,但是你去了。所以我们需要使 符合 Printable
以获得正确的重载。像往常一样,输入erasers 进行救援。
struct AnyPrintable:Printable {
let value:Printable
}
struct Generic< T> {
var args:T
func display(){
if let p = args as?可打印{
print(Printer.print(AnyPrintable(value:p)))
} else {
print(Printer.print(args))
}
}
}
Printable
需要一些方法,您只需将这些方法添加到 AnyPrintable
类型橡皮擦。)
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()
printableObj.display()
struct Generic<T>
struct PrintableGeneric<T: Printable>
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
print
is decided at compile time, not runtime. This is the thing that confuses people the most. They want to treat Swift like JavaScript where everything is dynamic. Swift likes to be static because then it can make sure your types are right and it can do lots of optimizations (and Swift loves to do compiler optimizations). So, compile time, what type is args
? Well, it's T
. Is T
known to be Printable
? No it is not. So it uses the non-Printable
version.Generic
using PrintableObj
, doesn't it know at that point that it's Printable
? Couldn't the compiler create a different version of display
at that point? Yes, if we knew at compile time every caller that would ever exist of this function, and that none of them would ever be extended to be Printable
(which could happen in a completely different module). It's hard to solve this without creating lots of weird corner cases (where internal things behave differently than public things for instance), and without forcing Swift to proactively generate every possible version of display
that might be required by some future caller. Swift may improve in time, but this is a hard problem I think. (Swift already suffers some performance reductions so that public generics can be specialized without access to the original source code. This would make that problem even more complicated.)T
isn't Printable
. But what if we had a type that was unambiguously Printable
that we knew at compile time and lived inside this function? Would it work then? func display() {
if let p = args as? Printable {
print(Printer.print(p))
} else {
print(Printer.print(args))
}
}
if-let
actually does exactly what you want it to do. p
gets assigned. It's Printable
. But it still calls the non-Printable function. ?!?!?!?!Printable
itself does not conform to Printable
. Yeah, I don't get it either, but there you go. So we need to make something that does conform to Printable
in order to get the right overload. As usual, type erasers to the rescue.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
requires some methods, you'd just add those methods to the AnyPrintable
type eraser.)Printer
. It's just way too confusing and fragile. It looks so nice, but it blows up all the time.