通用方法重写不在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

上一篇: Generic method override not working in swift

下一篇: Should I reuse OAuth 2.0 access tokens?