使用Array.map而不是array.map

时间:2015-10-25 15:33:58

标签: swift swift2

以下是我在Swift中可以做的事情:

extension Int {
  func square() -> Int { return self * self }
}

然后像这样称呼它:3.square(),它给了我9。另外,我可以这样做:Int.square(3),它会给我() -> (Int)。因此,Int.square(3)()9

但是,如果我写let array = [1, 2, 3]; Array.map(array),则会显示错误Cannot convert value of type 'Array<Int>' to expected argument of type '[_]'

问题是,我怎么能以这种方式使用Array.map?

修改 好的,我会尝试详细解释我的问题。现在,我的功能如下:

func map<T, U>(f: T -> U) -> [T] -> [U] {
  return { ts in
    ts.map(f)
  }
}

它可以工作,但仅适用于数组。有许多类型都有map函数,并且为每种类型声明全局函数都不是很好。所以,让我们说C型有地图函数C<T> -> (T -> U) -> C<U>

另外,假设我有f函数,将A -> B -> C转换为B -> A -> C

所以,看起来我可以这样做:

let array = [1, 2, 3]
let square: Int -> Int = {$0 * $0}
map(square)(array) // [1, 4, 9], works fine
f(Array.map)(square)(array) // Error

问题不在于代码可读性,而在于Swift的类型系统是如何工作的。

2 个答案:

答案 0 :(得分:2)

在带有square的示例中,编译器可以推断表达式的类型。换句话说:

let f = Int.square(3)

相同
let f:() -> Int = Int.square(3)

但是,map是一个在闭包返回类型上参数化的泛型函数:

public func map<T>(@noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]

因此,这会产生错误,因为编译器不知道T是什么:

let f = Array<Int>.map([1, 2, 3])

但是,您可以明确地告诉它T是这样的:

let f: ((Int) throws -> Int) throws -> [Int] = Array.map([1, 2, 3])
try! f({$0 * $0})

我认为这回答了关于方形和地图的第一个问题。我不完全理解你关于转换A - &gt;的其余问题。 B - &gt; C至B - &gt; A - &gt; C.也许你可以提供关于f的外观的更多信息。

答案 1 :(得分:2)

Array.map函数定义为:

public func map<T>(self: [Self.Generator.Element]) -> (@noescape Self.Generator.Element throws -> T) rethrows -> [T]

这里的问题是编译器无法推断transform函数或T的返回类型。所以你必须通过以下两种方式来定义它:

// variable declaration
let mapping: (Int -> Int) throws -> [Int] = Array.map(array)

// or (especially useful for further function calls)
aFunction(Array.map(array) as (Int -> Int) throws -> [Int])

您还可以看到map功能被标记为rethrows,其被&#34;翻译&#34;如果您使用该功能,请throws。 (它看起来像一个错误,但闭包没有rethrows这可能是造成这种行为的原因。)

所以函数f看起来像这样,以便与Array.map一起使用:

// where
// A is the array
// B is the function
// C the type of the returned array
func f<A, B, C>(f2: A -> (B throws -> C)) -> B -> (A throws -> C) {
    return { b in
        { a in
            try f2(a)(b)
        }
    }
}

// or with a forced try! so you don't have to use try
func f<A, B, C>(f2: A -> (B throws -> C)) -> B -> A -> C {
    return { b in
        { a in
            try! f2(a)(b)
        }
    }
}

// call f (use try if you use the first implementation)
let square: Int -> Int = {$0 * $0}
f(Array.map)(square)