为什么Swift类型系统尝试将类型转换为错误的预期参数

时间:2016-06-24 06:30:02

标签: generics type-systems swift3 swift-extensions xcode8

使用Xcode 8 beta,swift 3第二个扩展无法编译。我不明白这是一个快速的错误还是一个已知的限制。

extension Array {
    func scanl<T>(initial: T, combine:(Iterator.Element, T) -> T) -> [T] {
        guard let first = self.first else { return [] }
        return [initial] + Array(self.dropFirst()).scanl(initial: combine(first, initial), combine: combine)
    }
}


extension Array {
    func scanl<T>(combine: (Iterator.Element, T) -> T) -> [T] {
        guard let first = self.first else { return [] }
        return Array(self.dropFirst()).scanl(initial:first, combine:combine)// Cannot convert value of type '(Element, T) -> T' To expected argument type '(_, _) -> _'
    }
}

(元素,T) - &gt; T确实是函数的类型。 所以我无法理解为什么编译器期望() - &gt; __ 什么是这种类型意味着“我不关心类型”

1 个答案:

答案 0 :(得分:1)

这不是错误或限制,编译器无法在编译时确定first在您的第二个扩展中属于T类型{{1}不必与T相同。在两个闭包中,编译器都知道Iterator.Element的类型为first,但编译器无法知道它是否也是Iterator.Element类型。

在你的第一个扩展中,你只使用T作为first闭包的第一个参数,它只需要类型combine,所以一切都很好。

但是,在第二个扩展中,您尝试将Iterator.Element作为参数传递给期望类型为first的参数(initial),并且编译器无法知道{{1}确实属于T类型(与用于调用双参数first的{​​{1}}闭包使用的类型T相同),即T } combine的{​​{1}}类型。这可以通过第二个扩展的可选绑定子句中scanlIterator.Element的尝试类型转换(self)轻松兑换。

T

如果您构造一个扫描一个类型的数组以构造另一个类型的数组的示例,那么as?first不一定必须属于同一类型的事实是显而易见的,例如< / p>

T

如果您只希望您的extension Array { func scanl<T>(combine: (Iterator.Element, T) -> T) -> [T] { guard let first = self.first as? T else { return [] } return Array(self.dropFirst()).scanl(initial: first, combine: combine) } } 方法及其收集器生成相同类型的数组(正如正在扫描的那个),那么您不需要包含通用Iterator.Element,但可以使用在上面的扩展程序中使用T代替/* scant [Int] array to construct [String] array */ let foo = [1, 2, 3, 4, 5] let bar = foo.scanl(initial: "0") { String($0) + $1 } print(bar) // ["0", "10", "210", "3210", "43210"]