[英]How to constraint generic type to another generic type in Swift?
I'd like to do something like this: 我想做这样的事情:
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)
}
}
So later, for example, I can apply a Config to a UILabel: 因此,例如,稍后,我可以将Config应用于UILabel:
class RedViewConfig<T:UIView> : Config<T> {
func configure(x:T) {
x.backgroundColor = .redColor();
}
}
let label = UILabel()
Config.apply(RedViewConfig(), to:label)
Or extend Config classes: 或扩展Config类:
class RedLabelConfig<T:UILabel> : RedViewConfig<T> {
func configure(x:T) {
super.configure(x)
x.textColor = .redColor();
}
}
Config.apply(RedLabelConfig(), to:label)
I tried to do it, but I couldn't constraint classes. 我尝试这样做,但是我不能约束类。 So I tried with protocols and associated types, but when subclassing I found problems ( like this ) when overriding the associated type.
因此,我尝试使用协议和关联类型,但是在子类化时,在重写关联类型时发现了问题( 例如 )。
Do you actually need the generic parameter B
? 您实际上是否需要通用参数
B
? If your argument to:
was typed as A
as well, it could be any subtype of A
. 如果您的参数
to:
也输入为A
,则它可以是A
任何子类型。 Like such: 像这样:
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())
Classes make this way too complicated. 类使这种方式过于复杂。 Inheritance is almost always a bad idea in Swift if you can possibly avoid it.
如果可以避免的话,在Swift中继承几乎总是一个坏主意。
Structs, though closer, still make this a bit over-complicated and restrictive. 结构虽然更接近,但仍然使它过于复杂和受限。
Really, these configurators are just functions. 实际上,这些配置器只是功能。 They take a thing and they do something to it, returning nothing.
他们拿东西,然后对它做点什么,什么也没返回。 They're just
T -> Void
. 它们只是
T -> Void
。 Let's build a few of those. 让我们构建其中一些。
func RedViewConfig(view: UIView) { view.backgroundColor = .redColor() }
func VisibleConfig(view: UIView) { view.hidden = false }
And we can use them pretty easily: 我们可以很容易地使用它们:
let label = UILabel()
VisibleConfig(label)
We can compose them (like super
, but without the baggage) if their types are compatible: 如果它们的类型兼容,我们可以组成它们(像
super
,但没有行李):
func RedLabelConfig(label: UILabel) {
RedViewConfig(label)
label.textColor = .redColor()
}
We can pass them around in data structures, and the compiler will apply the right covariance for us: 我们可以在数据结构中传递它们,编译器将为我们应用正确的协方差:
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) }
Now if we want other syntaxes, we can build those pretty easily too. 现在,如果我们需要其他语法,我们也可以轻松构建它们。 Something more like your original:
更像您的原始作品:
func applyConfig<T>(f: T -> Void, to: T) {
f(to)
}
applyConfig(VisibleConfig, to: label)
or even closer to your original: 甚至更接近您的原始照片:
struct Config {
static func apply<T>(config: T -> Void, to: T) { config(to) }
}
Config.apply(VisibleConfig, to: label)
The point is that just using functions here makes everything very flexible without adding any of the complexity of class inheritance or even structs. 关键是,仅在此处使用函数就可以使一切变得非常灵活,而无需增加类继承甚至结构的复杂性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.