【发布时间】:2020-10-11 13:51:10
【问题描述】:
我正在观看有关 Julia 的有关 Multiple Dispatch 的视频,并且很好奇我是否可以在 Swift 中编写类似的东西。我看到 Swift 依赖于 Julia 似乎在运行时确定类型的编译器,但我也发现了一些我不了解 Swift 的地方。
为什么下面的函数encounters 会在两个参数属于同一类型的 Pet 时工作,但在一个是 Cat 而另一个是 Dog 时却不行?
例如下面的两个函数起作用
encounters(Arturo, Gabby) // both Cat
encounters(Cc, Bb) // both Dog
但这些会导致编译器错误
泛型参数“T”的参数冲突(“Cat”与“Dog”)
encounters(Arturo, Bb) // Cat and Dog
encounters(Bb, Arturo) // Dog and Cat
protocol Pet: Equatable {
var name: String { get }
}
struct Cat: Pet {
let name: String
}
struct Dog: Pet {
let name: String
}
let Arturo = Cat(name: "Arturo")
let Gabby = Cat(name: "Gabby")
let Bb = Dog(name: "Bb")
let Cc = Dog(name: "Cc")
func encounters<T: Pet>(_ a: T, _ b: T) {
var verb: String
switch (a, b) {
case is (Cat, Dog):
verb = meet(a as! Cat, b as! Dog)
case is (Dog, Dog):
verb = meet(a as! Dog, b as! Dog)
case is (Cat, Cat):
verb = meet(a as! Cat, b as! Cat)
case is (Dog, Cat):
verb = meet(a as! Dog, b as! Cat)
default:
fatalError()
}
print("\(a.name) meets \(b.name) and \(verb)")
}
func meet(_ a: Cat, _ b: Cat) -> String {
return "Slinks"
}
func meet(_ a: Cat, _ b: Dog) -> String {
return "Hisses"
}
func meet(_ a: Dog, _ b: Dog) -> String {
return "Howles"
}
func meet(_ a: Dog, _ b: Cat) -> String {
return "Barks"
}
【问题讨论】:
-
在这个例子中没有必要使用泛型,如果你要与显式类型进行比较,你可以简单地使用
func encounters(_ a: Pet, _ b: Pet)。 -
@ClausJørgensen 我确实尝试过,但我收到错误
Protocol 'Pet' can only be used as a generic constraint because it has Self or associated type requirements -
那是因为您在协议中添加了
:Equatable,这在大多数情况下并不是您的意思。这意味着符合的类型本身必须是 Equatable 的。这并不意味着 Pet 本身就是 Equatable。协议不能符合其他协议,因此 Pet 不可能是 Equatable。无论如何,您在此代码中不依赖 Equatable。 -
请注意,需要添加
fatalError()默认值是一个线索,表明您在这里走错了路并与语言作斗争。在某些情况下fatalError是合适的,但在这种情况下,它表明您已经在类型系统之外徘徊,并且正在运行时检查预期在编译时检查的内容。如果您添加了 Snake 类型的 Pet(例如,可以在完全不同的模块中添加),此代码将崩溃。
标签: swift generics protocols multiple-dispatch