|
|
1
6
是的,似乎有矛盾。Self关键字用作返回类型时,显然意味着“Self作为Self的实例”。例如,给定此协议
我们不能按如下方式实现它
因为我们得到一个编译器错误(“无法将‘return’类型的返回表达式转换为‘Self’类型”),如果我们违反doReturn()的约定并返回Self而不是other,则该错误将消失。我们不会写字
因为这仅在最终类中允许,即使Swift支持协变返回类型。(以下内容实际编译。)
另一方面,正如您所指出的,Return的子类可以“覆盖”Self要求,并愉快地遵守ReturnsReceived的合同,就像Self是符合类名称的简单占位符一样。
我可能错了,但我认为:
也就是说,在这里,关于Self的精确语义的任何选择都不一定会改变事情,您的代码说明了编译器很容易被欺骗的情况之一,它所能做的最好的事情就是生成代码,将检查推迟到运行时。在这种情况下,应该委托给运行时的检查与强制转换有关,在我看来,您的示例揭示的一个有趣的方面是,在特定的位置,Swift似乎 不 授权任何事情,因此不可避免的崩溃比应该发生的更为剧烈。 Swift能够在运行时检查强制转换。让我们考虑下面的代码。
在这里,我们创建一个SuperMario并将其向下转换为FireFlowerMario。这两个类并非无关,我们向编译器保证(as!)我们知道我们在做什么,所以编译器保持原样,并编译第二行和第三行。然而,程序在运行时失败,抱怨它
在第二行尝试演员阵容时。这不是错误或令人惊讶的行为。例如,Java也会做同样的事情:编译代码,在运行时失败并出现ClassCastException。重要的是,应用程序在运行时可靠地崩溃。 您的代码是欺骗编译器的一种更复杂的方法,但归根结底是同一个问题:有一个SuperMario而不是FireFlowerMario。不同的是,在您的情况下,我们不会收到温和的“无法投射”消息,但在真正的Xcode项目中,在调用throwFireballs()时会出现一个突然而可怕的错误。 在相同的情况下,Java失败(在运行时),出现了我们在上面看到的相同错误(ClassCastException),这意味着它在对queryFriend()返回的对象调用throwFireballs()之前,会尝试转换(到FireFlowerMario)。字节码中存在显式的checkcast指令很容易证实这一点。 相反,就我目前所见,Swift在调用之前不尝试任何强制转换(编译代码中没有调用任何强制转换例程),因此一个可怕的、未捕获的错误是唯一可能的结果。相反,如果您的代码生成了运行时“无法转换”错误消息,或类似的友好消息,我会对该语言的行为完全满意。 |
|
|
2
4
这里的问题似乎违反了合同:
您定义
现在,什么时候
您可以这样修复:
为什么编译器允许它?我想很难捕捉到这样的东西。对于
所以实际上
|