通用方法重写不在swift中工作 [英] Generic method override not working in swift

查看:143
本文介绍了通用方法重写不在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专注于 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 被赋值。它是可打印。但它仍然称为非打印功能。

这个地方我个人认为Swift目前刚刚破解,希望能够修复。它甚至可能是一个错误。问题是 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 中以这种方式使用泛型重载。这只是太混乱和脆弱的方式。它看起来非常好,但它总是爆炸。


There is a protocol Printable and a struct Printer from a 3rd Party.

protocol Printable {}

struct Printer {

    static func print<T>(object: T) -> String {
        return "T"
    }

    static func print<T: Printable>(object: T) -> String {
        return "Printable"
    }

}

Now i am making a generic

struct Generic<T> {

    var args: T

    func display() {
        print(Printer.print(args))
    }

}

and two structs

struct Obj {}
struct PrintableObj: Printable {}
var obj = Generic(args: Obj())
var printableObj = Generic(args: PrintableObj())

When i call the display functions on both of them.

obj.display()

displays T

printableObj.display()

displays T but i want it to print "Printable"

One solution i can think of is having two different generics

struct Generic<T>
struct PrintableGeneric<T: Printable>

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.

struct Generic<T> {
    var args: T
    func display() {
        print(Printer.print(args))
    }
}

The correct overload to choose for 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.

But when Swift specializes 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.)

OK, so we get that. 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))
    }
}

Oh so close... but not quite. This almost works. The 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. ?!?!?!?!

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 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))
        }
    }
}

And this will print the way you wanted. (On the assumption that Printable requires some methods, you'd just add those methods to the AnyPrintable type eraser.)

Of course the right answer is not to use generic overloads this way in Printer. It's just way too confusing and fragile. It looks so nice, but it blows up all the time.

这篇关于通用方法重写不在swift中工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆