Swift的函数式编程详解

2020-01-08 22:43:30丽君

b = a
a += "world"
print a # hello, world
print b # hello,</pre><p>Swift 的数据结构的 Persist 性质跟 Python 有点类似。需要注意的是,Swift 有变量和常量两种概念, 变量使用var声明,常量使用let声明,使用var声明的时候,Swift 中的字符串的行为跟 Python 相似, 因此修改字符串可以被理解为生成了一个新的字符串并修改了指针。同样, 使用var声明的数组和字典也都是可变的。</p><p>在 Swift 中使用let声明的对象不能被赋值,基本数据结果也会变得不可变,但是情况更复杂一点。</p><pre class="brush:js;toolbar:false">let aDict = ["k1":"v1"]
let anArray = [1, 2, 3, 4]
aDict["k1"] = "newVal" // !! will fail !!
anArray.append(5) // !! will fail !!
anArray[0] = 5 // anArray = [5, 2, 3, 4] now !</pre><p>从上面的代码中可以看出,使用let声明的字典是完全不可变的,但是数组虽然不可以改变长度, 却可以改变数组元素的值!Swift 的文档中指出这里其实是将 Array 理解为定长数组从而方便编译优化, 来获得更好的访问性能。</p><p>综上所述,对象是否可变的关系其实略有复杂的,可以总结为:</p><ol class=" list-paddingleft-2"><li><p>使用var和let,Int和String类型都是不可变的,但是var时可以对变量重新赋值</p></li><li><p>使用let声明的常量不可以被重新赋值</p></li><li><p>使用let声明的Dictionary是完全不可变的</p></li><li><p>使用let声明的Array长度不可变,但是可以修改元素的值</p></li><li><p>使用let声明的类对象是可变的</p></li></ol><p>综上所述,即使是使用let声明的对象也有可能可变,因此在多线程情况下就无法达到“无副作用”的要求了。</p><p>此外 Swift 的函数虽然没有指针,但是仍通过参数来修改变量的。只要在函数的参数定义中加入inout关键字即可。 这个特性很有 C 的风格。</p><p>个人觉得在支持通过元组来实现多返回值的情况下,这个特性不但显得鸡肋,也是一个导致程序产生“副作用”的特性。 Swift 支持这样的特性,恐怕更多的是为了兼容 Objective-C 以及方便在两个语言之间搭建 Bridge。</p><pre class="brush:js;toolbar:false">func inc(inout a:Int) {
  a += 1
}
var num = 1
inc(&num) // num = 2 now!</pre><p>综上所述,使用 Swift 自带的数据结构并不能很好的实现“无副作用”的“纯函数式”编程, 它并没有比 Python、Ruby 这类语言走的更远。幸好作为一种关注度很高的语言, 已经有开发者为其实现了一套完全满足不可变要求的数据结构和库:Swiftz。 坚持使用let和 Swiftz 提供的数据结构来操作,就可以实现“纯函数式”编程。</p><p><strong>总结</strong></p><p>在我看来,Swift 虽然实现了很多其他语言的亮点特性,但是总体实现来说并不是很整齐。 它在函数式编程方面添加了很多特性,但在控制副作用方面仅能达到平均水准。 有些特性看起来像是为了兼容原来的 Objective-C 才加入的。</p><p>Swift 写起来相对比 Objective-C 更方便一点,脱离 Xcode 这样的 IDE 来写也是应该是可以的。 目前 Swift 只支持集中少量的原生数据结构而没有标准库,更不具备跨平台特性,这是一个缺点。 在仔细阅读了文档之后发现 Swift 本身的语法细节还是很多的,就比如switch分置语句的用法就有很多内容。 入门学习的容易程度并没有原来想象的那么好。我个人并不觉得这门语言会对其他平台的开发者有很大吸引力。</p><p>Swift 是一门很强大的语言,在其稳定版本发布之后我认为我会从 Objective-C 转向 Swift 来进行编程, 它在未来很可能成为 iOS 和 Mac 开发的首选。</p>