Swift 3泛型函数含糊不清

时间:2017-07-20 15:06:26

标签: swift generics ambiguous

我需要一个函数来解决类中的不同依赖项。 但是出现了编译错误。 是否有可能创建该泛型函数或Swift中存在一些编译器约束?

import Foundation

protocol Client: class {
    var description: String { get }
}
final class ImportantPerson : Client {
    var description: String {
        return "Important person"
    }
}

protocol Order: class {
    var description: String { get }
}
final class LastOrder : Order {
    var description: String {
        return "Last order"
    }
}

final class A {

    fileprivate func resolveDependency<T>() -> T {
        return resolve() as T
    }

    private func resolve() -> Client {
        return ImportantPerson()
    }
    private func resolve() -> Order {
        return LastOrder()
    }

}

let a = A()
let client: Client = a.resolveDependency()
let order: Order = a.resolveDependency()

print("Client: \(client.description)")
print("Order: \(order.description)")

编辑:这个问题不是关于Swift是否允许创建两个仅由返回类型不同的函数。我知道这是可能的。我认为在编译器中存在一些人为约束,但在基本逻辑中不应该允许从上下文中推断出所需的类型。

2 个答案:

答案 0 :(得分:0)

让我们把自己置于编译器之中。想象一下,这不会导致错误,并且您有一个具有不同输出的签名。

每当你调用resolveDependency<T>() -> T时,编译器都会返回一个类型T,这是一个符合你案例协议的实例。

在您的代码中,您使用符合相同协议的不同实例调用此方法。在那个阶段,编译器不知道这一点。它只知道你已经传递了一个T的实例,它需要给你一个T

形状的结果

在此之前没有问题。一旦执行

return resolve() as! T

编译器会感到困惑。我有一个T,但我不知道我会打电话给哪个resolve() ...我所知道的是我有一个T。我怎么知道这是Order还是Client

为了防止这种混淆,我们有编译时错误。至少Swift就是这种情况。 (我不知道其他语言是如何工作的)

您需要使用不同的签名定义不同的方法,并相应地转换您的类型以获得类似的结果

fileprivate func resolveDependency<T>() -> T {
  // check if this is an Order
  resolveForOrder()

  // check if this is a Client
  resolveForClient()
}

private func resolveForOrder() -> Order {
  return LastOrder()
}

private func resolveForClient() -> Client {
  return ImportantPerson()
}

这就像试图用汽车修理工修理航天飞机发动机一样。是的,他们都有一个引擎,他们都使用燃料,但机械师只知道如何修理你的汽车发动机他不是火箭科学家(!)

答案 1 :(得分:0)

此代码可以正常工作:

import Foundation

protocol Client: class {
    var description: String { get }
}
final class ImportantPerson : Client {
    var description: String {
        return "Important person"
    }
}

protocol Order: class {
    var description: String { get }
}
final class LastOrder : Order {
    var description: String {
        return "Last order"
    }
}

final class A {

    fileprivate func resolveDependency<T>() -> T {
        if T.self == Client.self {
            return resolve() as Client as! T
        } else {
            return resolve() as Order as! T
        }
    }

    private func resolve() -> Client {
        return ImportantPerson()
    }
    private func resolve() -> Order {
        return LastOrder()
    }

}

let a = A()
let client: Client = a.resolveDependency()
let order: Order = a.resolveDependency()

print("Client: \(client.description)")
print("Order: \(order.description)")

但我相信编译器应该自己解决 if else 子句,它并不像我想的那么难。 当编译器尝试匹配类似的类型时,编译器中也存在一些错误:

    switch T.self {
    case is Client:
        return resolve() as Client as! T
    default:
        return resolve() as Order as! T
    }