首页 > 解决方案 > Swift 函数重载 - 在传递 Any 对象时使用特定参数(代替 Any 参数)调用 func

问题描述

我有3个结构:

struct Address: Codable {
    var addressLine1: String
}
struct Person: Codable {
    var name: String
}
struct Order: Codable {
    var person: Person?
    var address: Address?
}

在我的 ViewController 类中,我使用 Mirror 来访问 Order 中的每个属性:

let address = Address(addressLine1: "Some unknown address")
let person = Person(name: "Some unknown name")
let order = Order(person: person, address: address)

let newOrderMirror = Mirror(reflecting: order)
newOrderMirror.children.forEach {
    display(child: $0.value)
}

在 ViewController 中,我实现了 3 个显示功能:

func display(child: Any) {
    // this should never get called
    print(child)
}

func display(child: Person) {
    print(child)
}

func display(child: Address) {
    print(child)
}

在上述情况下,它总是在调用func display(child: Any),但是我希望它调用具有特定参数的函数。有没有什么方法可以在没有类型转换的情况下实现这一点?

当然,这将起作用:

    newOrderMirror.children.forEach {
        if let bs = $0.value as? Person {
            display(child: bs)
        } else if let addr = $0.value as? Address {
            display(child: addr)
        }
        display(child: $0.value)
    }

有没有其他优雅的方法可以在不使用的情况下实现所需的行为if-let + typecasting

更新1:

在这里找到相关的东西 -如何调用更具体的重载方法

更新 2:

我可以通过以下步骤实现更简洁的解决方案:

  1. 使用 func display() 声明 Displayable 协议
  2. 让每个模型实现这个协议
  3. 在每个孩子的 forEach 中,我可以绑定和类型转换到协议并在其上调用 display 方法

然而,这对我来说似乎是一个丑陋的解决方案,因为 Model 现在有两个职责 - i。处理/存储数据,ii。处理数据的显示方式。在我看来,第二个责任对于实现控制器或演示者类而不是模型类来说更合理,因此我想避免这条路

标签: swiftoverloadingswift-mirror

解决方案


children属性指向Mirror.Child元素的集合,它实际上是由 aString和 an组成的元组Any。因此,镜像的每个子项都将编译类型设置为Any(这是必需的,因为镜像实际上可以应用于任何类型)。

由于上述原因,并且考虑到重载是一种编译时特性,编译器无法选择除带有Any参数的重载之外的其他重载。

您可以对此采取的一种解决方法是更改​​第一个display()重载的主体:

func display(child: Any) {
    switch child {
    case let person as Person: display(person)
    case let address as Address: display(address)
    default: print(child)
    }
}

func display(child: Person) {
    print(child)
}

func display(child: Address) {
    print(child)
}

基本上你仍然需要帮助编译器选择正确的函数来调用。


推荐阅读