Swift 为特定类型的集合添加协议一致性
当Swift 为特定类型的集合添加协议一致性,swift,Swift,当元素是特定类型时,我想将协议一致性添加到集合 作为我试图做的一个例子,考虑下面的(设计的)代码,将数值绑定到表达式中的占位符。 typealias占位符=字符串 枚举数{ 大小写整数(Int64) 箱子浮动(双) } 协议绑定{ func绑定(到表达式:表达式,用于占位符:占位符) } 类表达式{ 变量值:[占位符:数字]=[:] } 扩展名Int:Bindable{ func绑定(到表达式:表达式,用于占位符:占位符){ 表达式.values[占位符]=.integer(Int64(self
元素
是特定类型时,我想将协议一致性添加到集合
作为我试图做的一个例子,考虑下面的(设计的)代码,将数值绑定到表达式中的占位符。
typealias占位符=字符串
枚举数{
大小写整数(Int64)
箱子浮动(双)
}
协议绑定{
func绑定(到表达式:表达式,用于占位符:占位符)
}
类表达式{
变量值:[占位符:数字]=[:]
}
扩展名Int:Bindable{
func绑定(到表达式:表达式,用于占位符:占位符){
表达式.values[占位符]=.integer(Int64(self))
}
}
扩展浮动:可绑定{
func绑定(到表达式:表达式,用于占位符:占位符){
表达式.values[占位符]=.float(双精度(自))
}
}
类生成器{
let expression=expression()
func集(u值:T,用于占位符:占位符){
bind(to:expression,for:placeholder)
}
}
使用此代码可以设置Int
和Float
值:
let builder=builder()
builder.set(Int(10),表示“Int”)
生成器设置(浮动(10),表示“浮动”)
现在,当元素
为Int
时,我希望能够使用现有的集合(:for:)
绑定数组的和:
扩展可绑定,其中Self:Collection,Element==Int{
func绑定(到表达式:表达式,用于占位符:占位符){
expression.values[placeholder]=.integer(Int64(self.reduce(0,+))
}
}
//错误:实例方法“set(\:for:)”要求“[Int]”符合“Bindable”
生成器集合([1,2],表示“总和”)
我错误地认为扩展将使[Int]
符合可绑定的要求
我可以通过向Builder
添加一个额外的集合(:for:)
函数来解决这个问题:
类生成器{
func集(值:T,用于占位符:占位符),其中T.Element==Int{
bind(to:expression,for:placeholder)
}
}
元素==Int的扩展集合{
func绑定(到表达式:表达式,用于占位符:占位符){
expression.values[placeholder]=.integer(Int64(self.reduce(0,+))
}
}
生成器集合([1,2],表示“总和”)
但是我想理解为什么第一种方法不起作用。您认为这会使所有[Int]
都符合可绑定的:
extension Bindable where Self: Collection, Element == Int {
上述事实说明:
将此bind
方法添加到Bindable
的所有符合项,该符合项也是Int
的集合
你扩展了错误的东西。您应该在[Int]
上编写扩展,而不是Bindable
的符合项。你想说:
将此bind
方法添加到Int
的所有集合中(并使其符合Bindable
)
上面的代码实际上不起作用。。。因为不幸的是,您无法通过扩展使一个协议与另一个协议保持一致,所以下一个选择是对阵列执行此操作:
extension Array : Bindable where Element == Int {
func bind(to expression: Expression, for placeholder: Placeholder) {
expression.values[placeholder] = .integer(Int64(self.reduce(0, +)))
}
}
如果确实希望set
接受通用集合/序列,可以为接受序列的set
添加另一个重载:
func set<S, T>(_ values: S,
for placeholder: Placeholder,
withIdentity identity: T,
andReductionFunction reductionFunction: (T, S.Element) -> T)
where S: Sequence, S.Element: Bindable, T: Bindable {
values.reduce(identity, reductionFunction).bind(to: expression, for: placeholder)
}
您认为这使所有的[Int]
都符合可绑定的要求:
extension Bindable where Self: Collection, Element == Int {
上述事实说明:
将此bind
方法添加到Bindable
的所有符合项,该符合项也是Int
的集合
你扩展了错误的东西。您应该在[Int]
上编写扩展,而不是Bindable
的符合项。你想说:
将此bind
方法添加到Int
的所有集合中(并使其符合Bindable
)
上面的代码实际上不起作用。。。因为不幸的是,您无法通过扩展使一个协议与另一个协议保持一致,所以下一个选择是对阵列执行此操作:
extension Array : Bindable where Element == Int {
func bind(to expression: Expression, for placeholder: Placeholder) {
expression.values[placeholder] = .integer(Int64(self.reduce(0, +)))
}
}
如果确实希望set
接受通用集合/序列,可以为接受序列的set
添加另一个重载:
func set<S, T>(_ values: S,
for placeholder: Placeholder,
withIdentity identity: T,
andReductionFunction reductionFunction: (T, S.Element) -> T)
where S: Sequence, S.Element: Bindable, T: Bindable {
values.reduce(identity, reductionFunction).bind(to: expression, for: placeholder)
}
谢谢你的回答。我尝试了你最初提到的第一种方法,但显然不起作用。看来真正的答案是,至少现在不能这样做。也许在未来的Swift版本中@sbooth如果您只想set
能够接受Collection
s,您可以添加另一个重载。请参阅编辑。中提到了这一点,Swift团队似乎认为这会带来比解决问题更多的问题。感谢您的回答。我尝试了你最初提到的第一种方法,但显然不起作用。看来真正的答案是,至少现在不能这样做。也许在未来的Swift版本中@sbooth如果您只想set
能够接受Collection
s,您可以添加另一个重载。见编辑。在中提到了这一点,似乎Swift团队认为这会带来比解决问题更多的问题。