我想创建一个可以将数组聚合成一种类型的泛型函数。我将用一个愚蠢而简单的例子来解释。
我们说我得到了这段代码:
class Entity {
var someElement: Int
}
现在我已经在Array extension
中编写了这个函数,以便我可以在任何数组上使用它:
/**
* An aggregation function. The first closure extracts the useful data in a new object, the second one aggregates two items of the same type in one.
*
* The algorithm works from front to back
*
* @return the aggregated value or nil if the array is empty
*/
func aggregate<R>(translation: (T) -> R, aggregation: (R, R) -> R) -> R? {
if count == 0 {
return nil
}
if count == 1 {
return translation(self.first!)
}
var calc = translation(self.first!)
for item in 1..<count {
calc = aggregation(calc, translation(self[item]))
}
return calc
}
我想像这样使用它:
let array: [Entity] = ... // something fills the array
array.aggregate(
{
item in
return item.someElement
}, aggregation: {
(item1, item2) in
return item1 + item2
}
)
但我得到了这个疯狂的错误:Cannot convert the expression's type '((($T5) -> ($T5) -> $T4) -> (($T5) -> $T4) -> $T4, aggregation: (($T7, ($T7, $T8) -> ($T7, $T8) -> $T6) -> ($T7, ($T7, $T8) -> $T6) -> $T6, (($T7, $T8) -> ($T7, $T8) -> $T6, $T8) -> (($T7, $T8) -> $T6, $T8) -> $T6) -> (($T7, ($T7, $T8) -> $T6) -> $T6, (($T7, $T8) -> $T6, $T8) -> $T6) -> $T6)' to type 'R'
。
世界上发生了什么?在Xcode中,当我检查item
的类型时,它是<<error type>>
,因此它甚至无法通过它进行编译。我是否需要在函数调用中指定R是什么?
答案 0 :(得分:2)
看起来Swift无法推断第一个闭包的类型。如果您将对聚合的调用更新为明确提供类型:
array.aggregate(
{
(item: Entity)->Int in
return item.someElement
}, aggregation: {
(item1, item2) in
return item1 + item2
}
)
它编译/运行正常。
有趣的是,如果您不使用显式返回,则推理可以正常工作:
array.aggregate(
{
item in
item.someElement
}, aggregation: {
(item1, item2) in
return item1 + item2
})
(array.aggregate({ $0.someElement},+)
也可以正常工作)
P.S。如果您对替代方案感兴趣,可以按如下方式重写aggregate
:
extension Array {
func aggregate<R>(translation: T -> R, aggregation: (R, R) -> R) -> R? {
return self.first.map { fst in
dropFirst(self).reduce(translation(fst)) { aggregation($0, translation($1)) }
}
}
}