Swift中的变形金刚
变形金刚?
直到最近,每当我听到“功能是Swift中的头等公民!” ,我希望将闭包作为方法中的回调或完成块传递,也许是要从异步网络调用中获取一些数据,如下所示:
func fetchUsers(_补全:@转义([用户])->无效){
// ..
}
或将代码块分配给变量:
让闭包= {
令a = 1 + 2 + 3
打印(a)
}
真好 我们也知道Swift的map
和其他高阶函数将闭包作为参数。 多进行一些挖掘,这将打开一个门户,进入另一个维度,即编写代码的功能方式。 等等,暂时不要下载RxSwift,我们可以从这里开始一些基础知识。
我对函子/单子的可疑理论
原来, map
, flatMap
, reduce
之类的东西代表了Swift的功能风格。 Haskell是一种纯函数式语言,在Haskell的fmap
和liftM
之间直接映射到Swift的map
和flatMap
。 这些实体称为函子或单子 。
这些来自类别理论。 如果我被迫开枪简要介绍我对该概念的非常有限的理解,我会说,
我们对基本类型执行操作的方式,函子/单子使我们即使在上下文中也可以对此类进行操作。
例如:
func addTwo(int:Int)-> Int {
返回int + 2
}
让三个= addTwo(int:1)// 3
让threeOrMore = [1,2,3] .map(addTwo)// [3,4,5]
‘1’是我们要在其上执行addTwo
的整数,此处的map
允许我们方便地对’1’进行操作,即使它包含在上下文(在本例中为数组)中也是如此。
如果您想深入研究Functors / Monads / Applicatives ,我建议从这个令人惊奇的帖子和这个令人惊奇的演讲开始。 为了简洁起见,这里我们仅关注它们的用法。
用法
- 选装件
可选的 有自己的地图! 我们可以在不解开它们的情况下对值进行运算,而nil将会被处理。
展览A:
let greeting = Optional.some(“ Hi”)。map {$ 0 +“,Ssup?”}
//可选(“嗨,你好吗?”)
let rude = Optional.none.map {$ 0 +“,Ssup?”}
//零
- 可选清单
另一个超级方便的用法是处理可选对象的集合。
看看这个将几个函子链接在一起的示例:
让问候= [Optional.some(“ Hi”),
可选。无,
Optional.some(“ Hello”),
零]
让真正的=问候
.flatMap {$ 0}
.map {“ \($ 0),Ssup吗?”}
// [“嗨,Ssup?”,“你好,Ssup?”]
- 转换模型
假设我们有一个UserInfo
数据模型列表,我们希望将其转换为特定于我们视图的视图模型UserViewDetails
。 我们有一个帮助程序功能,负责转换:
//数据模型
struct UserInfo {
var firstName: 字符串 !
var lastName: String !
var DOB: 日期 !
var houseNumber: Int !
var建筑: String !
var street: 字符串 !
}
//查看模型
struct UserViewDetails {
var fullName: 字符串
变量年龄: 整数
变量地址: 字符串
}
//帮手
func details(_ info:UserInfo)-> UserViewDetails {
让名称=“ \(info.firstName)\(info.lastName)”
让年龄= Int(Date()。timeIntervalSince(info.DOB)/ 31536000)
让地址=“ \(info.houseNumber,info.building,info.street)”
返回UserViewDetails(全名:姓名,年龄:年龄,地址:地址)
}
使用我们通常的命令式方法,我们会做类似的事情,
var viewUsersImp = [ UserViewDetails ]()
对于用户 {
让viewUser = details( user )
viewUsersImp.append(viewUser)
}
但是使用我们所看到的,使用map
我们可以将其重写为:
让viewUsers =用户。 map ({(user)-> UserViewDetails in
返回详细信息(用户)
})
用一些语法糖减少多余的装饰,
让viewUsers =用户。 地图 {用户位于
返回详细信息(用户)
}
// 要么,
让viewUsers =用户。 地图 {details($ 0)}
// 要么,
让viewUsers =用户。 地图 (详细信息)
不用说,我们已经将4行代码精简为4个音节。
- 创建多个实例
发疯,从值列表创建实例列表。
struct Dog {
var 品种 :字符串
}
[“ Pug”,“ Rottweiler”,“ Golden Retriever”]。map(Dog.init)
//对象
// [{ 繁殖 “ Pug”},{ 繁殖 “ Rottweiler”},{ 繁殖 “金毛猎犬”}]]
…
尝试编写自己的Swift的Array
或Optional
的map函数实现肯定有助于使它们神秘化。 我鼓励尝试该练习。
我们可以广泛地编写自己的自定义“ 地图”,以在日常代码中利用这些功能。 可能性是无止境的。
结论
- 我觉得用这种方式编写代码更加简洁,整洁且噪音小。
- 与我们必须提供的
for-in
不同,它也更具声明性
一步一步地说明我们想要做什么。 - 我也觉得这种方法会迫使我们编写更纯净的函数。 我不想在上述
details(_:)
方法中添加任何不相关的代码,例如,以增加用户数量或修改任何全局变量,从而避免产生副作用。
我们肯定可以从功能范式中借鉴很多东西来编写更简洁的代码。 MVVM设计模式就是另一个这样的例子,我们借用Observables将模型绑定到我们的视图。 再换一天
请指出改进之处或在评论中分享您如何使用高阶函数使生活变得轻松,或者这对您而言是新闻。 非常感谢您的阅读!