一尘不染

协议功能返回自我

swift

我有一个协议P,它返回对象的副本:

protocol P {
    func copy() -> Self
}

和一个实现P的类C:

class C : P {
    func copy() -> Self {
        return C()
    }
}

但是,是否Self在出现以下错误时放入返回值:

无法将类型“ C”的返回表达式转换为类型“ Self”

我也试着回来C

class C : P {
    func copy() -> C  {
        return C()
    }
}

这导致以下错误:

非最终类“ C”中的方法“ copy()”必须返回Self以符合协议“ P”

除了我class Cfinalie做前缀的情况外,没有任何作用:

final class C : P {
    func copy() -> C  {
        return C()
    }
}

但是,如果我想对C进行子类化,那么将无济于事。有没有办法解决?


阅读 263

收藏
2020-07-07

共1个答案

一尘不染

问题是您要保证编译器无法证明您会保留。

因此,您创建了以下承诺:调用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) {
    // Perform your copying here.
  }
}

这就是您应该执行复制的方式。

我们可以进一步迈出这一步,但是它使用了dynamicType,而且我还没有对其进行广泛的测试以确保它始终是我们想要的,但是它应该是正确的:

protocol Copyable {
  func copy() -> Self
  init(copy: Self)
}

class C : Copyable {
  func copy() -> Self {
    return self.dynamicType(copy: self)
  }

  required init(copy: C) {
    // Perform your copying here.
  }
}

在这里,我们保证有一个初始化程序为我们执行拷贝,然后我们可以在运行时确定要调用的那个,从而为我们提供了您要查找的方法语法。

2020-07-07