11.1.2.2 使用不可变数据结构

为了演示了以不可变风格,写相同的代码,但不一定必须使用函数式列表;即使使用标准的 List<T> 类型,我们一样能够避免修改集合。然而,不幸的是,要确保不意外修改列表,可能很难。

处理不允许修改的类型,有更好的方法。可以使用真正不可变类型,比如,第三章的FuncList<T>,或者 .NET Framework 中的 ReadOnlyCollection<T>;即使使用 IEnumerable<T>,一样可以得到良好的安全保障;可用于枚举任何集合类型的元素(包括可变的和不可变的),但不给提供任何直接的方式,修改底层集合;如果我们打算从其他线程修改集合,仍然可能有意想不到的结果,但并非这个例子中的情况。

我们使用IEnumerable <T> 实现同样的例子。LoadPlaces 和 PrintLongest方法变化不大,因此,这里就省略了;PrintMultiWord 方法更有意义:因为IEnumerable <T> 类型是不可变的,所以,前面的 RemoveAll策略,就不能再用了。此前,我们用这个方法从集合中删除所有单字地名,副作用使这个方法更难推断。如果我们想使用不可变类型,得到同样的结果,必须更加明确,如清单11.5 所示。

清单11.5 使用IEnumerable<T> 实现 PrintMultiWord (C#)

IEnumerable<string> PrintMultiWord(IEnumerable<string>names) {

varnamesSpace = names.Where(s => s.Contains(" "));     [1]

Console.WriteLine("Withspace: {0}", namesSpace.Count());

returnnamesSpace;     [2]

}

处理不可变数据结时,是不能修改集合的,因此,该方法首先创建一个新的集合,只包含有多字的地名[1]。我们也实现了前面显式实现的副作用,所以,这个方法现在返回新的集合。当然,这不是真正的副作用,就是返回值。它实现了相同的结果,使调用者能够使用多字地名列表,如果他们想用的话[2]。

我们第一个例子是在所有的地名中找到最长的,第二个例子(输出“NewYork”)返回包含个空格的最长地名。清单11.6 是使用新的函数来实现这两个例子。

清单11.6 输出最长和多字最长地名(C#)


IEnumerable<string> places =

LoadImmutablePlaces();

PrintMultiWord(places);

PrintLongest(places);     [1]


IEnumerable<string> places =

LoadImmutablePlaces();

var placesSpace =

PrintMultiWord(places);    [2]

PrintLongest(placesSpace);    [3]

现在,我们已经更明确地进行了修改,就不要对结果有所不同而感到奇怪了。在左侧的版本中,输出“Grantchester”[1],而选择包含空格的最长地名的版本,则输出“NewYork”。

清单11.6 还表明,使用不可变数据类型,可以让推断程序,并决定哪些重构是有效的更容易。在左侧的例子中,我们可以改变PrintMultiWord 和PrintLongest 的顺序,输出结果仍然相同(只是顺序相反);在清单11.6 的右侧,就不能改变调用的顺序,因为值placesSpace 是第一次调用的结果[2]。

因此,重构函数式代码时,可以更容易跟踪计算的依赖关系。我们可以看到,如果一个函数以其他调用的结果作为参数值,说明这个函数依赖于其他调用。因为,这在代码中是明确可见的,我们不可能犯意外重构的错误,由于错误修改的代码将不能通过编译,这在使用单元测试时也是非常有用的。

时间: 2024-08-08 09:18:36

11.1.2.2 使用不可变数据结构的相关文章

11.1.2.1 使用可变数据结构

在清单11.4 中,可以看到两个函数,处理的集合保存了前面示例的地名.这一次,我们使用C#,把地名保存在标准的List<T> 类型中,它是可变的. 清单11.4 处理保存在List<T> 中的地名(C#) List<string> LoadPlaces() {     [1] returnnew List<string> { "Seattle", "Prague", "NewYork", "

2.2.2 使用不可变数据结构

函数程序表示数据,使用数据结构,我们会在第五.七章讨论数据结构.虽然数据结构的概念通常更简单,但是,我们现在要讨论复合数据类型,比如 C# 值类型,或类.从第一章我们知道,函数编程中的数据结构是不可变的. 不可变数据结构的概念,逻辑上可以从不可变值绑定的概念推导出来.典型的数据结构包含字段声明.如果我们不可变性的概念从变量声明扩展到字段声明,就能得出一切都是不可变的.在 C# 中,不可变类字段要使用 readonly 限定符,而 F# 中所有的数据结构都是不可变的,是默认情况.F# 并不是严格的

有用函数编程

<序> 感谢 关于本书 关于封面 第一部分 学习函数式思维 第一章 不同的思维 1.1 什么是函数式编程? 1.2 通往有用函数编程之路 1.3 用函数式编程提高生产力 1.3.1 函数范式 1.3.2 声明式编程风格 1.3.3 了解程序的执行 1.3.4 设计并发友好的应用程序 1.3.5 函数风格怎样形成代码 1.4 函数式编程演示样例 1.4.1 用声明式风格表达意图 1.4.1.1 用 LINQ 处理数据 1.4.1.2 用 XAML 描写叙述用户界面 1.4.1.3 声明式函数动画

C++11新特性之五——可变参数模板

有些时候,我们定义一个函数,可能这个函数需要支持可变长参数,也就是说调用者可以传入任意个数的参数.比如C函数printf(). 我们可以这么调用. printf("name: %s, number: %d", "Obama", 1); 那么这个函数是怎么实现的呢?其实C语言支持可变长参数的. 我们举个例子, double Sum(int count, ...) { va_list ap; double sum = 0; va_start(ap, count); fo

外部排序-第11章-《数据结构题集》习题解析-严蔚敏吴伟民版

习题集解析部分 第11章 外部排序 ——<数据结构题集>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑       相关测试数据下载  链接? 数据包       本习题文档的存放目录:数据结构\▼配套习题解析\▼11 外部排序    

Python3 官方文档翻译 - 5 数据结构

这章会更详细地描述了一些你已经学过的知识,同时添加一些新东西. 5.1 List进阶 下面是关于List的所有方法 list.append(x) 将元素添加至列表尾,相当于a[len(a):] = [x] list.extend(L) 通过将L中所有元素添加至列表尾来扩展list,相当于a[len(a):] = L list.insert(i, x) 在指定位置插入元素.第一个参数是插入位置前一个的下标,a.insert(0,x)是在列表头插入,a.insert(len(a),x)相当于a.ap

34 个今年11月最受欢迎的 JavaScript 库

作者:Iren Korkishko 译者:前端小智 来源:dev 点赞再看,养成习惯 本文 GitHub:github.com/qq449245884… 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料.欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西. 直接开门见山,看看有哪些好用受欢迎的库值得我们使用. 1.nodemon GitHub: github.com/remy/nodemo… GitHub Stars: 19.6 k 在编写调试Node.js项

C++11模版元编程

1.概述 模版元编程(template metaprogram)是C++中最复杂也是威力最强大的编程范式,它是一种可以创建和操纵程序的程序.模版元编程完全不同于普通的运行期程序,它很独特,因为模版元程序的执行完全是在编译期,并且模版元程序操纵的数据不能是运行时变量,只能是编译期常量,不可修改,另外它用到的语法元素也是相当有限,不能使用运行期的一些语法,比如if-else,for等语句都不能用.因此,模版元编程需要很多技巧,常常需要类型重定义.枚举常量.继承.模板偏特化等方法来配合,因此编写模版元

python 数据结构 初学时没太注意却发现很有用的点点滴滴

1. list.extend(L) 将指定列表中的所有元素附加到另一个列表的末尾:相当于a[len(a):] = L. 2. list.pop([i]) 删除列表中指定位置的元素并返回它.如果未指定索引,a.pop()将删除并返回列表中的最后一个元素.(i 两边的方括号表示这个参数是可选的,而不是要你输入方括号.你会在 Python 参考库中经常看到这种表示法). 3. list.index(x) 返回列表中第一个值为 x 的元素的索引.如果没有这样的元素将会报错. 4. list.count(