问题在于你做出了一个编译器无法证明你会遵守的承诺。
因此,你创建了这个承诺:调用copy()
将返回其自身类型,完全初始化。
但是你却这样实现了copy()
:
func copy() -> Self {
return C()
}
现在我是一个未覆盖copy()
方法的子类。 我返回一个C
,而不是完全初始化的Self
(这是我承诺过的)。所以这不好。怎么样:
func copy() -> Self {
return Self()
}
好的,那段代码不能编译通过,即使它能编译通过,也没用。子类可能没有默认构造函数,所以 D()
可能甚至不合法。(见下文)
好吧,那怎么样:
func copy() -> C {
return C()
}
是的,但它并不返回 Self
。它返回C
。你仍然没有遵守承诺。
“但ObjC可以做到!”嗯,有点吧。主要是因为它不像Swift那样关心你是否遵守了承诺。如果在子类中未实现copyWithZone:
,则可能无法完全初始化对象。编译器甚至不会警告你已经这样做了。
“但ObjC中的大多数内容都可以翻译成Swift,并且ObjC有NSCopying
。” 是的,它确实有,这是它的定义:
func copy() -> AnyObject!
所以你可以做相同的事情(这里没有感叹号是没问题的):
protocol Copyable {
func copy() -> AnyObject
}
那句话的意思是“我不保证你会得到任何东西。”你也可以这样说:
protocol Copyable {
func copy() -> Copyable
}
这是一个你可以兑现的承诺。
但是我们可以暂时考虑一下C++,并且记住有一个我们可以实现的承诺。我们可以承诺自己及所有子类将实现特定种类的初始化程序,并且Swift将执行此操作(因此可以证明我们在说实话):
protocol Copyable {
init(copy: Self)
}
class C : Copyable {
required init(copy: C) {
}
}
这就是你应该执行复制的方式。
我们可以更进一步,但它使用了 dynamicType
,我还没有进行全面测试以确保它始终是我们想要的,但应该是正确的:
protocol Copyable {
func copy() -> Self
init(copy: Self)
}
class C : Copyable {
func copy() -> Self {
return self.dynamicType(copy: self)
}
required init(copy: C) {
}
}
在这里,我们承诺有一个初始化器为我们执行复制,然后我们可以在运行时确定要调用哪一个,从而给我们你正在寻找的方法语法。
[[[self class] alloc] init]
。所以我的问题是,有没有一种类型安全的方式来调用当前类并调用init方法? - aeubanksself.dynamicType()
。你调用的初始化程序必须声明为required
,因为在Swift中初始化程序并不总是被继承的。 - newacct