了解Swift平面地图语法

时间:2016-08-17 11:57:13

标签: ios swift syntax

下面函数'parseB'中用于flatMap的语法使用括号,而不是大括号。

struct Episode {
    let id: String
    let title: String
}

extension Episode {
    init?(dictionary: [String: AnyObject]) {
        guard let id = dictionary["id"] as? String, title = dictionary["title"] as? String else { return nil }
        self.id = id
        self.title = title
    }
}

func parseA(dictionaries: [[String: AnyObject]]) -> [Episode] {
    return dictionaries.flatMap { dic in Episode.init(dictionary: dic)}
}

func parseB(dictionaries: [[String: AnyObject]]) -> [Episode] {
    return dictionaries.flatMap (Episode.init)
}

有一个看起来像这样的平面地图实现

public func flatMap<U>(@noescape f: (Wrapped) throws -> U!) rethrows -> U!

阅读本文我仍然无法理解,在上面的例子中,剧集上的init没有括号。

有时候,斯威夫特非常擅长推断内容很难理解正在发生的事情。有人可以帮我理解为什么剧集的init方法不使用括号吗?

...flatMap (Episode.init)

参考1:https://talk.objc.io/episodes/S01E01-networking 参考2:https://github.com/objcio/S01E01-networking

4 个答案:

答案 0 :(得分:3)

让我们从一个简单的代码片段开始

[1,2,3].map(String.init) // ["1", "2", "3"]

这里map遍历数组的每个元素[1,2,3],每次都将第n个元素传递给String初始化器。

这是因为

  1. 数组具有Int作为通用元素
  2. String有一个init接受Int仅作为参数
  3. 为什么( ... )代替{ ... }

    在这种情况下,我们使用此.map(...)而不是此.map{ ... },因为我们将map传递给其他地方定义的函数(以及初始值设定项),我们不直接编写函数/闭合。

    就像我们写的那样

    func isEven(n:Int) -> Bool {
        return n % 2 == 0
    }
    
    [1,2,3].filter(isEven) // [2]
    

    这里我们将过滤上面定义的函数,因此我们使用()

    当然我们也可以使用{ ... }

    直接编写函数
    [1,2,3].filter { (n:Int) -> Bool in
        return n % 2 == 0
    }
    

    您的代码

    在您的代码中,这可行

    dictionaries.flatMap (Episode.init)
    

    因为Episode有一个init,它接受​​dictionaries中相同类型的元素。

    事实上,dictionaries的每个元素都具有此类型[String: AnyObject],并且Episode的init接受相同的类型。

    init?(dictionary: [String: AnyObject]) { ... }
    

答案 1 :(得分:1)

那是因为在Swift中,instance methods are curried functions。这意味着Episode.init是一个函数(实际上它是一个命名的闭包),它接收一个参数 - self,它恰巧(或不匹配)匹配flatMap期望的闭包的签名。 / p>

您的代码中发生的事情是您传递对flatMap期望的闭包的引用,而不是调用它,因为调用闭包只会返回一个Episode实例。

答案 2 :(得分:1)

尾随关闭快速您可以在Apple文档中找到它 https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html

flatMap等待类型为(A)->B的参数,但它可以是函数或闭包:

let initializer: (Int) -> String = String.init

相同

let closure:(Int) -> String = {return String($0)}

为简单起见,我们可以调用map方法:

[1,2,3].map(initializer) == [1,2,3].map(closure)

但是如果我们使用closure是最后一个参数,它可以写在方法之外,在我们的例子中map方法

[1,2,3].map(){return String($0)}

我们可以省略()

[1,2,3].map{return String($0)}

答案 3 :(得分:0)

class Employee {
    var name: String = ""

    init(name: String) {
        self.name = name
    }
}
  

实例方法是Swift中的Curried函数

这是一个curried函数,它接受一个参数String并返回一个Employee

let employeeFunc = Employee.init  //  (String) -> Employee

让我们在数组类型

上定义我们自己的地图功能
extension Array {
    func myMap <U> (f: (Element) -> U) -> [U] {
        var result = [U]()

        for element in self {
            result.append(f(element))
        }
        return result
    }
}


var allEmployee = [Employee]()
let names = ["Mario", "Luigi"]

您可以一次将值传递给curried函数。这个curried函数只期望一个参数

let firstEmployee = employeeFunc("Superman")

同样,我们可以将多个名称传递给多个Employee来创建实例

allEmployee = names.myMap(f: employeeFunc)

我们也可以这样映射

allEmployee = names.myMap(){ employeeFunc($0)}

让我们打印值

for employee in allEmployee {
    print (employee.name)
}