返回 Self 的协议函数 [英] Protocol func returning Self

查看:59
本文介绍了返回 Self 的协议函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a protocol P that returns a copy of the object:

protocol P {
    func copy() -> Self
}

和一个实现 P 的 C 类:

and a class C that implements P:

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

但是,无论我是否将返回值设为 Self 我都会收到以下错误:

However, whether I put the return value as Self I get the following error:

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

Cannot convert return expression of type 'C' to return type 'Self'

我也尝试返回 C.

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

这导致了以下错误:

非final类'C'中的方法'copy()'必须返回Self以符合协议'P'

Method 'copy()' in non-final class 'C' must return Self to conform to protocol 'P'

除了我在 class C 前面加上 final 前缀的情况外,没有任何作用,即:

Nothing works except for the case where I prefix class C with final ie do:

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

但是,如果我想将 C 子类化,那么什么都行不通.有没有办法解决这个问题?

However if I want to subclass C then nothing would work. Is there any way around this?

推荐答案

问题是你做出的承诺编译器无法证明你会遵守.

The problem is that you're making a promise that the compiler can't prove you'll keep.

所以你创建了这个承诺:调用 copy() 将返回它自己的类型,完全初始化.

So you created this promise: Calling copy() will return its own type, fully initialized.

但是你以这种方式实现了copy():

But then you implemented copy() this way:

func copy() -> Self {
    return C()
}

现在我是一个不覆盖 copy() 的子类.我返回一个 C,而不是一个完全初始化的 Self(我承诺过).所以这不好.怎么样:

Now I'm a subclass that doesn't override copy(). And I return a C, not a fully-initialized Self (which I promised). So that's no good. How about:

func copy() -> Self {
    return Self()
}

好吧,那不会编译,但即使编译了,也不好.子类可能没有简单的构造函数,所以 D() 甚至可能不合法.(虽然见下文.)

Well, that won't compile, but even if it did, it'd be no good. The subclass may have no trivial constructor, so D() might not even be legal. (Though see below.)

好的,怎么样:

func copy() -> C {
    return C()
}

是的,但这不会返回 Self.它返回C.你仍然没有遵守你的诺言.

Yes, but that doesn't return Self. It returns C. You're still not keeping your promise.

但 ObjC 可以做到!"嗯,有点.主要是因为它不在乎你是否像 Swift 那样遵守承诺.如果您未能在子类中实现 copyWithZone:,您可能无法完全初始化您的对象.编译器甚至不会警告你你已经这样做了.

"But ObjC can do it!" Well, sort of. Mostly because it doesn't care if you keep your promise the way Swift does. If you fail to implement copyWithZone: in the subclass, you may fail to fully initialize your object. The compiler won't even warn you that you've done that.

但是 ObjC 中的大部分内容都可以转换为 Swift,并且 ObjC 具有 NSCopying."是的,它是这样定义的:

"But most everything in ObjC can be translated to Swift, and ObjC has NSCopying." Yes it does, and here's how it's defined:

func copy() -> AnyObject!

所以你也可以这样做(这里没有 ! 的理由):

So you can do the same (there's no reason for the ! here):

protocol Copyable {
  func copy() -> AnyObject
}

那是说我不承诺你会得到什么."你也可以说:

That says "I'm not promising anything about what you get back." You could also say:

protocol Copyable {
  func copy() -> Copyable
}

这是你可以做出的承诺.

That's a promise you can make.

但我们可以暂时考虑一下 C++,并记住我们可以做出承诺.我们可以保证我们和我们所有的子类都将实现特定类型的初始化器,而 Swift 将强制执行(因此可以证明我们说的是实话):

But we can think about C++ for a little while and remember that there's a promise we can make. We can promise that we and all our subclasses will implement specific kinds of initializers, and Swift will enforce that (and so can prove we're telling the truth):

protocol Copyable {
  init(copy: Self)
}

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

这就是你应该如何进行复制.

And that is how you should perform copies.

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

We can take this one step further, but it uses dynamicType, and I haven't tested it extensively to make sure that is always what we want, but it should be correct:

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.
  }
}

这里我们保证有一个初始化程序为我们执行复制,然后我们可以在运行时确定调用哪个,为我们提供您正在寻找的方法语法.

Here we promise that there is an initializer that performs copies for us, and then we can at runtime determine which one to call, giving us the method syntax you were looking for.

这篇关于返回 Self 的协议函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆