调用了错误的通用重载函数
Wrong generic overload function called
我想了解为什么忽略泛型方法的 where 子句
我在 Swift 3 中做了一个简单的用例(如果你想 fiddle 使用它,你可以在操场上复制代码):
//MARK: - Classes
protocol HasChildren {
var children:[Human] {get}
}
class Human {}
class SeniorHuman : Human, HasChildren {
var children: [Human] {
return [AdultHuman(), AdultHuman()]
}
}
class AdultHuman : Human, HasChildren {
var children: [Human] {
return [YoungHuman(), YoungHuman(), YoungHuman()]
}
}
class YoungHuman : Human {}
//MARK: - Generic Methods
/// This method should only be called for YoungHuman
func sayHelloToFamily<T: Human>(of human:T) {
print("Hello \(human). You have no children. But do you conform to protocol? \(human is HasChildren)")
}
/// This method should be called for SeniorHuman and AdultHuman, but not for YoungHuman...
func sayHelloToFamily<T: Human>(of human:T) where T: HasChildren {
print("Hello \(human). You have \(human.children.count) children, good for you!")
}
好的,现在让我们运行进行一些测试。如果我们有:
let senior = SeniorHuman()
let adult = AdultHuman()
print("Test #1")
sayHelloToFamily(of: senior)
print("Test #2")
sayHelloToFamily(of: adult)
if let seniorFirstChildren = senior.children.first {
print("Test #3")
sayHelloToFamily(of: seniorFirstChildren)
print("Test #4")
sayHelloToFamily(of: seniorFirstChildren as! AdultHuman)
}
输出为:
Test #1
Hello SeniorHuman. You have 2 children, good for you!
Test #2
Hello AdultHuman. You have 3 children, good for you!
Test #3
Hello AdultHuman. You have no children. But do you conform to protocol? true
//Well, why are you not calling the other method then?
Test #4
Hello AdultHuman. You have 3 children, good for you!
//Oh... it's working here... It seems that I just can't use supertyping
嗯...显然,要使 where
协议子句起作用,我们需要传递一个符合协议定义的强类型。
仅使用超类型是不够的,即使在测试 #3 中很明显给定的实例实际上符合 HasChildren
协议。
那么,我在这里遗漏了什么,这是不可能的吗?您是否有一些链接提供有关正在发生的事情的更多信息,或有关 [=13= 的更多信息] 子句或子类型及其一般行为?
我已经阅读了一些有用的资源,但 none 似乎对它为什么不起作用有详尽的解释:
调用方法的类型在编译时选择。编译器对您的类型了解多少?
if let seniorFirstChildren = senior.children.first {
seniorFirstChildren
是 Human
因为这就是 children
的声明方式。我们不知道 child
是成人还是老年人。
但是,考虑一下:
if let seniorFirstChildren = senior.children.first as? AdultHuman {
现在编译器知道 seniorFirstChildren
是 AdultHuman
并且它将调用您期望的方法。
你必须区分静态类型(编译期间已知的类型)和动态类型(运行时已知的类型)。
来自 the Language Guide - Type Casting:
Checking Type
Use the type check operator (is
) to check whether an instance is of
a certain subclass type. The type check operator returns true
if the
instance is of that subclass type and false
if it is not.
类型检查运算符 is
在 运行时解析 ,而使用第一个 children
调用 sayHelloToFamily
的重载解析AdultHuman
实例的成员(绑定到 seniorFirstChildren
),因为参数在 编译时 解析(在这种情况下,它被键入为 Human
,这不符合 HasChildren
)。如果您明确告诉编译器 seniorFirstChildren
是一个 AdultHuman
实例(使用不安全的 as! AdultHuman
),那么编译器自然会利用此信息来选择更具体的重载。
我想了解为什么忽略泛型方法的 where 子句
我在 Swift 3 中做了一个简单的用例(如果你想 fiddle 使用它,你可以在操场上复制代码):
//MARK: - Classes
protocol HasChildren {
var children:[Human] {get}
}
class Human {}
class SeniorHuman : Human, HasChildren {
var children: [Human] {
return [AdultHuman(), AdultHuman()]
}
}
class AdultHuman : Human, HasChildren {
var children: [Human] {
return [YoungHuman(), YoungHuman(), YoungHuman()]
}
}
class YoungHuman : Human {}
//MARK: - Generic Methods
/// This method should only be called for YoungHuman
func sayHelloToFamily<T: Human>(of human:T) {
print("Hello \(human). You have no children. But do you conform to protocol? \(human is HasChildren)")
}
/// This method should be called for SeniorHuman and AdultHuman, but not for YoungHuman...
func sayHelloToFamily<T: Human>(of human:T) where T: HasChildren {
print("Hello \(human). You have \(human.children.count) children, good for you!")
}
好的,现在让我们运行进行一些测试。如果我们有:
let senior = SeniorHuman()
let adult = AdultHuman()
print("Test #1")
sayHelloToFamily(of: senior)
print("Test #2")
sayHelloToFamily(of: adult)
if let seniorFirstChildren = senior.children.first {
print("Test #3")
sayHelloToFamily(of: seniorFirstChildren)
print("Test #4")
sayHelloToFamily(of: seniorFirstChildren as! AdultHuman)
}
输出为:
Test #1
Hello SeniorHuman. You have 2 children, good for you!
Test #2
Hello AdultHuman. You have 3 children, good for you!
Test #3
Hello AdultHuman. You have no children. But do you conform to protocol? true
//Well, why are you not calling the other method then?
Test #4
Hello AdultHuman. You have 3 children, good for you!
//Oh... it's working here... It seems that I just can't use supertyping
嗯...显然,要使 where
协议子句起作用,我们需要传递一个符合协议定义的强类型。
仅使用超类型是不够的,即使在测试 #3 中很明显给定的实例实际上符合 HasChildren
协议。
那么,我在这里遗漏了什么,这是不可能的吗?您是否有一些链接提供有关正在发生的事情的更多信息,或有关 [=13= 的更多信息] 子句或子类型及其一般行为?
我已经阅读了一些有用的资源,但 none 似乎对它为什么不起作用有详尽的解释:
调用方法的类型在编译时选择。编译器对您的类型了解多少?
if let seniorFirstChildren = senior.children.first {
seniorFirstChildren
是 Human
因为这就是 children
的声明方式。我们不知道 child
是成人还是老年人。
但是,考虑一下:
if let seniorFirstChildren = senior.children.first as? AdultHuman {
现在编译器知道 seniorFirstChildren
是 AdultHuman
并且它将调用您期望的方法。
你必须区分静态类型(编译期间已知的类型)和动态类型(运行时已知的类型)。
来自 the Language Guide - Type Casting:
Checking Type
Use the type check operator (
is
) to check whether an instance is of a certain subclass type. The type check operator returnstrue
if the instance is of that subclass type andfalse
if it is not.
类型检查运算符 is
在 运行时解析 ,而使用第一个 children
调用 sayHelloToFamily
的重载解析AdultHuman
实例的成员(绑定到 seniorFirstChildren
),因为参数在 编译时 解析(在这种情况下,它被键入为 Human
,这不符合 HasChildren
)。如果您明确告诉编译器 seniorFirstChildren
是一个 AdultHuman
实例(使用不安全的 as! AdultHuman
),那么编译器自然会利用此信息来选择更具体的重载。