如何接受一个非常通用但动态的类型作为子类的参数?

时间:2014-12-11 23:27:38

标签: generics swift types arguments

鉴于受this question on Code Review启发的this answer on Stack Overflow,我带着这个问题回到Stack Overflow。

假设我有一个包含多个子类的类,请说UIControl。我想用一个方法扩展这个类。该方法应该采用相同类型的对象作为其参数之一。但对于任何和所有这些类的子类,此方法只应接受其自己类型的参数。例如,UIButton应仅接受UIButton类型的参数,而UILabel应仅接受UILabel类型的参数。

已尝试过什么?

首先:

func foo<T: UIControl>(arg: T) {
    // do stuff
}

这适用于编译和运行,但它不执行。无论我实际调用UIControl的类型,我都可以传递任何foo子类。

下一步:

func foo(arg: Self) {
    // do stuff
}

此外:

func foo<T: Self>(arg: T) {
    // do stuff
}

这些都不起作用,但这是一个想法。不编译,不能像这样使用Self

也尝试过:

func foo(arg: self.dynamicType) {
    // do stuff
}

func foo(arg: typeof(self)) {
    // do stuff
}

仍然没有一个工作 - 不会编译(这些错误的错误,合理的......)。

然后:我没有想法。

现在,一般来说,我们可能会争辩说使用泛型是好的,因为我们只会用它来做我们约束泛型的父有能力,但如果我们想要的话怎么办?将此对象返回给其他人,他们知道并需要它作为比我们定义的父类型更具体的东西吗?

例如,如果我们正在编写一个函数来添加回调:

func doCallBack<T: UIControl>(callback: (T) -> Void)) {
    callback(self)
}

对我们来说重要的是,在回调块中,用户可以使用并引用参数作为其特定类型,但是当我们调用doCallBack时,对我们来说也很重要。 UIButton T类型UIButton只能是doCallBack,但当我们在UILabel上调用T时,UILabel对于每种UIControl类型,类型只能是{{1}}等。

这可以完成吗?

1 个答案:

答案 0 :(得分:1)

  

但对于任何和所有这些类的子类,此方法应该   只接受自己类型的参数。

对于继承的工作方式,这实际上是不可能的。

考虑

class Foo : UIControl
class Bar : Foo

因此Foo必须有一个带有签名func foo(arg: Foo)的方法。由于BarFoo的子类,因此它将继承签名为func foo(arg: Foo)的方法(或使用该签名的方法覆盖它)。在任何情况下,参数类型都不能比Foo窄,因为Bar根据继承的要求,不能成为Foo的正确替代品。因此,Bar foo方法不能只接受自己类型的参数&#34;。