如何将泛型类型约束到Swift中的另一个泛型类型?

时间:2015-11-29 13:55:37

标签: swift generics inheritance

我想做这样的事情:

class Config<T> {
  func configure(x:T)
  // constraint B to be subclass of A
  class func apply<A,B:A>(c:Config<A>, to:B) {
    c.configure(to)
  } 
}

所以稍后,例如,我可以将配置应用于UILabel:

class RedViewConfig<T:UIView> : Config<T> {
  func configure(x:T) {
    x.backgroundColor = .redColor();
  } 
}

let label = UILabel() 
Config.apply(RedViewConfig(), to:label)

或者扩展Config类:

class RedLabelConfig<T:UILabel> : RedViewConfig<T> {
  func configure(x:T) {
    super.configure(x)
    x.textColor = .redColor();
  } 
}

Config.apply(RedLabelConfig(), to:label)

我试图这样做,但我无法限制类。所以我尝试使用协议和相关类型,但在子类化时,我在覆盖关联类型时发现了问题(like this)。

2 个答案:

答案 0 :(得分:1)

您确实需要通用参数B吗?如果您的参数to:也被输入为A,则它可以是A的任何子类型。像这样:

class View {}
class LabelView : View {}

class Config<T> {
  func configure(x:T) { print ("Configured: \(x)") }  
}

func applyConfig<A> (c:Config<A>, to:A) {
  c.configure(to)
}

applyConfig(Config<View>(), to: LabelView())

答案 1 :(得分:1)

类使这太复杂了。如果你可以避免继承,那么继承在Swift中几乎总是一个坏主意。

虽然结构更接近,但仍然使这有点过于复杂和限制。

真的,这些配置器只是功能。他们接受了一件事,他们为此做了一些事情,什么也没有回来。他们只是T -> Void。让我们构建其中的一些。

func RedViewConfig(view: UIView) { view.backgroundColor = .redColor() }
func VisibleConfig(view: UIView) { view.hidden = false }

我们可以很容易地使用它们:

let label = UILabel()
VisibleConfig(label)

如果他们的类型兼容,我们可以撰写它们(如super,但没有行李):

func RedLabelConfig(label: UILabel) {
    RedViewConfig(label)
    label.textColor = .redColor()
}

我们可以在数据结构中传递它们,编译器将为我们应用正确的协方差:

let configs = [RedLabelConfig, VisibleConfig]
// [UILabel -> ()]
// This has correctly typed visibleConfig as taking `UILabel`,
// even though visibleConfig takes `UIView`

// And we can apply them
for config in configs { config(label) }

现在,如果我们想要其他语法,我们也可以很容易地构建它们。更像你原来的东西:

func applyConfig<T>(f: T -> Void, to: T) {
    f(to)
}
applyConfig(VisibleConfig, to: label)

或者甚至更接近你原来的:

struct Config {
    static func apply<T>(config: T -> Void, to: T) { config(to) }
}

Config.apply(VisibleConfig, to: label)

重点是,在这里使用函数可以使一切变得非常灵活,而不会增加类继承甚至结构的任何复杂性。