新华一城书集店铺主页二维码
新华一城书集 微信认证
上海新华书店官方微信书店
微信扫描二维码,访问我们的微信店铺
你可以使用微信联系我们,随时随地的购物、客服咨询、查询订单和物流...

函数式与并发编程

101.48
运费: ¥ 5.00-20.00
库存: 3 件
函数式与并发编程 商品图0
函数式与并发编程 商品图1
函数式与并发编程 商品图2
函数式与并发编程 商品图3
函数式与并发编程 商品图4
函数式与并发编程 商品缩略图0 函数式与并发编程 商品缩略图1 函数式与并发编程 商品缩略图2 函数式与并发编程 商品缩略图3 函数式与并发编程 商品缩略图4

商品详情

产品特色.png

编辑推荐.png

《函数式与并发编程》主要围绕两个主题:函数式编程和并发编程。本书主要使用Scala 编写代码示例,逐一讲解各编程特性的用法和注意事项,是一本不可多得的工具书,强烈推荐给程序员们。笔者周围的程序员提到这两个主题时都存在一定的畏难情绪,这是正常的,也是可以理解的。程序员不仅需要丰富的编程经验,还要具备深厚的编程设计思维,而这并非一朝一夕就能形成的,需要经年累月的实战和经验积累。我并不推荐读者将本书从头读到尾,这样不利于理解和消化书中的知识点。建议具备一定的函数式编程和并发编程基础的读者建立场景和问题,通过解决问题的方式来学习本书,并在遇到问题时查阅本书。本书也可作为理解这两个主题的途径。

内容简介.png

现代语言支持的函数式和并发编程语言特性可能富有挑战性,即使是经验丰富的开发人员,当面对函数式与并发编程时,也可能心生畏惧。面向对象编程的程序员之所以畏惧这些特性,很可能是因为他们对这些特性的工作方式有所误解。为了消除误解,程序员应首先熟悉这些强大的特性背后的抽象概念。《函数式与并发编程》介绍了一系列核心的编程语言结构,可让你的编程工作变得高效起来,无论你使用的是哪种编程语言,你都能从中获益在当下的工作中,以及在未来的职业发展中。Charpentier用大量重点突出的小型Scala代码示例阐释了函数式与并发编程的关键概念,并通过完整的案例研究对前述技术和技巧进行深入的探究和阐释。这些技术和技巧将从一种语言传递到另一种语言包括Java的最新版本。利用函数式和并发编程语言特性,开发人员和程序员将能编写出易于理解、调试、优化和改进的优质代码。另外,本书还讨论了现代编程语言中常用的类型策略,包括类型推断、子类型、多态性、类型类、类型边界和变型。核心主题● 递归和尾递归● 模式匹配和代数数据类型● 可持久化结构和不可变性● 高阶函数和lambda表达式● 延迟求值和流● 线程和线程池● 原子性和锁● 同步和线程安全对象● 无锁、非阻塞模式● Future、Promise和函数并发编程

《函数式与并发编程》中的大部分代码示例都是使用Scala编写的,其中包含函数式与并发编程的许多标准特性;然而,读者不必事先了解Scala,而只需要熟悉一些基本概念,如类、方法、对象、类型、变量、循环和条件语句等。此外,读者在编程方面应有足够的经验,以免因为简单的语法问题而分心。

作者简介.png

Michel Charpentier 是美国新罕布什尔大学(UNH)计算机科学系的副教授。多年来,他一直致力于分布式系统、正式验证以及移动传感器网络等领域的研究。自 1999 年以来,他一直在UNH工作,目前正在讲授编程语言、并发性、形式验证和模型检查等课程。

目录简介.png

第I部分 函数式编程第1章 函数式编程的概念 31.1 什么是函数式编程 31.2 函数 41.3 从函数到函数式编程概念 51.4 小结 6第2章 编程语言中的函数 72.1 定义函数 72.2 合成函数 82.3 定义为方法的函数 92.4 定义为方法的运算符 102.5 扩展方法 102.6 局部函数 112.7 重复参数 122.8 可选参数 132.9 命名参数 132.10 类型参数 142.11 小结 16第3章 不可变性 173.1 纯函数和非纯函数 173.2 动作 183.3 表达式与语句 203.4 函数变量 223.5 不可变对象 233.6 可变状态的实现 243.7 函数式列表 253.8 混合编程 273.9 更新可变/不可变对象的集合 283.10 小结 30第4章 案例研究:active_passive集合 314.1 面向对象设计 314.2 函数值 334.3 函数对象 354.4 小结 36第5章 模式匹配与代数数据类型 385.1 函数开关 385.2 元组 395.3 选项 405.4 回顾函数式列表 415.5 树 435.6 示例:列表拉链 465.7 提取器 485.8 小结 49第6章 递归程序设计 516.1 递归的必要性 516.2 递归算法 536.3 递归算法的关键原理 556.4 递归结构 566.5 尾递归 586.6 尾递归函数示例 606.7 小结 63第7章 列表递归 647.1 等价的递归算法 647.2 遍历列表 657.3 返回列表 667.4 从执行堆栈中构建列表 687.5 多个/嵌套列表上的递归 697.6 除尾部以外的子列表递归 717.7 逆序创建列表 737.8 示例:排序 747.9 高效地构建列表 777.10 小结 78第8章 案例研究:二叉搜索树 798.1 二叉搜索树 798.2 二叉搜索树的整数集 808.3 未重新平衡情况下的实现 818.4 自平衡树 868.5 小结 90第9章 高阶函数 929.1 函数作为值 929.2 柯里化 959.3 函数字面量 969.4 函数与方法 999.5 单一抽象方法接口 1009.6 部分应用 1009.7 闭包 1049.8 控制反转 1079.9 小结 108第10章 标准高阶函数 10910.1 带有谓词参数的函数 10910.2 映射和遍历 11110.3 flatMap 11210.4 fold和reduce 11610.5 iterate、tabulate和unfold 11810.6 sortWith、sortBy、maxBy和minBy 11910.7 groupBy和groupMap 12010.8 标准高阶函数的实现 12110.9 foreach、map、flatMap和for推导式 12210.10 小结 124第11章 案例研究:文件树 12511.1 设计概述 12511.2 节点搜索辅助函数 12611.3 字符串表示 12611.4 构建树 12811.5 查询 13111.6 导航 13511.7 树形拉链 13511.8 小结 138第12章 延迟计算 13912.1 延迟求值的参数 13912.2 按名称参数 14012.3 控制抽象 14212.4 内部领域特定语言 14412.5 作为延迟求值列表的流 14512.6 管道流 14712.7 无限数据结构流 14812.8 迭代 14912.9 列表、流、迭代程序和视图 15112.10 字段和局部变量的延迟求值 15412.11 示例:子集和 15512.12 小结 157第13章 故障处理 15813.1 例外情况和特殊值 15813.2 使用Option 16013.3 使用Try 16013.4 使用Either 16213.5 高阶函数和管道 16313.6 小结 166第14章 案例研究:蹦床 16714.1 尾调用优化 16714.2 用于尾调用的蹦床函数 16814.3 Java中的尾调用优化 16914.4 处理非尾调用 17014.5 小结 174第15章 类型(及相关概念) 17515.1 类型策略 17515.2 类型集合 17915.3 类型服务 18015.4 抽象数据类型 18115.5 类型推断 18215.6 子类型 18515.7 多态性 18815.8 类型变换 19015.9 类型边界 19515.10 类型类 19915.11 小结 203第Ⅱ部分 并发编程第16章 并发编程的概念 20816.1 非顺序程序 20816.2 并发编程相关概念 21116.3 小结 211第17章 线程与不确定性 21317.1 执行线程 21317.2 使用lambda表达式创建线程 21417.3 多线程程序的不确定性 21517.4 线程终止 21617.5 测试和调试多线程程序 21817.6 小结 219第18章 原子性和锁 22018.1 原子性 22018.2 非原子操作 22218.3 原子操作和非原子复合操作 22318.4 锁 22618.5 内部锁 22718.6 选择锁目标 22918.7 小结 231第19章 线程安全对象 23219.1 不可变对象 23219.2 封装同步策略 23319.3 避免引用转义 23419.4 公用锁和私有锁 23519.5 利用不可变类型 23619.6 线程安全 23919.7 小结 240第20章 案例研究:线程安全队列 24220.1 作为列表对组的队列 24220.2 单个公用锁的实现 24220.3 单个私有锁的实现 24520.4 应用锁拆分 24720.5 小结 249第21章 线程池 25021.1 即发即弃异步执行 25021.2 示例:并行服务器 25221.3 不同类型的线程池 25421.4 并行集合 25621.5 小结 260第22章 同步 26122.1 同步的必要性 26122.2 同步器 26422.3 死锁 26522.4 使用线程转储调试死锁 26722.5 Java内存模型 26822.6 小结 272第23章 常用同步器 27423.1 锁 27423.2 锁存器和栅栏 27623.3 信号量 27823.4 条件 27923.5 阻塞队列 28423.6 小结 287第24章 案例研究:并行执行 28924.1 顺序引用实现 28924.2 每个任务一个新线程 29024.3 有界线程数 29124.4 专用线程池 29224.5 共享线程池 29324.6 有界线程池 29424.7 并行集合 29524.8 使用条件提交异步任务 29524.9 双信号量实现 29924.10 小结 300第25章 Future与Promise 30225.1 函数任务 30225.2 Future作为同步器 30325.3 超时、故障和取消 30625.4 Future变体 30725.5 Promise 30825.6 示例:线程安全缓存 30925.7 小结 311第26章 函数并发编程 31226.1 阻塞的正确性和性能问题 31226.2 回调 31426.3 Future的高阶函数 31626.4 Future的flatMap函数 31826.5 示例:重新访问并行服务器 31926.6 函数并发编程模式 32226.7 小结 325第27章 最小化线程阻塞 32727.1 原子操作 32727.2 无锁数据结构 33027.3 fork/join池 33227.4 异步编程 33327.5 actor 33427.6 反应流 33727.7 非阻塞同步 33827.8 小结 340第28章 案例研究:并行策略 34128.1 问题定义 34128.2 带超时的顺序实现 34228.3 使用invokeAny的并行实现 34428.4 使用CompletionService的并行实现 34528.5 Scala Future的异步实现 34628.6 带有CompletableFuture的异步实现 34828.7 缓存策略的结果 35028.8 小结 353

附录和词汇表通过扫描封底二维码获取附录 Java和Kotlin的特性 354词汇表 381

【前言】

在开始阅读本书之前,最好先思考一下编程语言和编程语言特性之间的区别。我相信,若能依仗一套通用的编程语言特性,开发人员肯定能从中获益,而且,无论是现在还是将来,对这些特性的深入了解都将有助于他们在各种编程语言中高效发挥。编程语言的世界丰富多样,并且一直在发展。作为一名开发人员,你需要适应变化并反复将编程技能从一种语言迁移至另一种语言。通过掌握一组核心特性,可以更加轻松地学习全新的编程语言。这些核心特性往往是当今编程语言所共享的,并且在许多未来的语言中也可能会用到。本书运用了大量代码示例来说明编程语言的特性这些示例主要运用Scala语言编写(原因将在稍后详述)。然而,这些概念在不同程度上与其他编程语言相关联,如Java、C 、Kotlin、Python、C井、Swift、Rust、Go、JavaScript之类的流行语言,以及任何未来可能出现的支持强类型以及函数式和/或并发编程的语言。若要领悟语言和特性之间的区别,不妨考虑以下编程任务:对给定列表中的每个数字执行随机移位(移位值在_10到10之间选取)。返回移位数字列表,并忽略所有非正值。Java程序员可能会按如下方式实现所需的功能:

Listlt;Integergt;randShift(Listlt;Integergt;numsRandomrand){varshiftedNums=newjava.util.ArrayListlt;Integergt;(nums.size());for(intnum:nums){intshifted=num rand.nextInt(_1011);if(shiftedgt;0)shiftedNums.add(shifted);}returnshiftedNums;}

Python程序员可能会按如下方式编写:

defrand_shift(numsrand):shifted_nums=[]fornuminnums:shifted=num rand.randrange(_1011)ifshiftedgt;0:shifted_nums.append(shifted)returnshifted_nums

尽管它们是用两种不同的语言编写的,但这两段代码都遵循类似的原理:创建一个新的空列表以保存移位的数字,将每个原始数字随机移位,并仅在它们为正值时将新值添加到结果列表中。就思路和目的而言,这两个程序是相同的。其他程序员可能会选择直接解决这个问题。下面是一个可能的Java变体:

Listlt;Integergt;randShift(Listlt;Integergt;numsRandomrand){returnnums.stream().map(num_gt;num rand.nextInt(_1011)).filter(shifted_gt;shiftedgt;0).toList();}

这个实现的细节现在并不重要它依赖于函数式编程概念,这将在本书第I部分中讨论。重要的是代码与先前的Java实现明显不同。可以使用Python编写类似的函数变体:

defrand_shift(numsrand):returnlist(filter(lambdashifted:shiftedgt;0map(lambdanum:num rand.randrange(_1011)nums)))

与第一个Python程序相比,这个实现显然更接近第二个Java变体。这4个程序演示了解决最初那个问题的两种不同的方式。它们在Java或Python中将命令式实现与函数式实现进行对比。从根本上区分这些程序的不是语言(Java与Python),而是它们使用的编程特性(命令式与函数式)。命令式变体(赋值语句、循环)和函数式变体(高阶函数、lambda表达式)中使用的编程语言特性独立于Java和Python而存在;事实上,它们在许多编程语言中都可用。我并不是说编程语言无关紧要。我们都知道,对于一个给定的任务,某些语言要比其他语言更适用。但我想强调的是跨语言扩展的核心特性和概念,尽管它们出现在不同的语法下。例如,经验丰富的Python程序员更可能以如下方式编写示例函数程序:

defrand_shift(numsrand):return[shiftedforshiftedin(num rand.randrange(_1011)fornuminnums)ifshiftedgt;0]

这段代码看起来与前面的Python代码不同细节并不重要。注意,函数map和filter在任何地方都不可见。不过,从概念上讲,这是同一个程序,只不过使用了一种称为列表推导的特殊Python语法,而非map和filter。这里需要理解的重要概念是map和filter(乃至更普遍的高阶函数,map和filter都是高阶函数的例子)而非列表推导。这种理解有两个方面的好处。首先,更多的语言支持高阶函数,而不是推导语法。例如,如果使用Java编程,则必须显式地(至少目前如此)编写map和filter。其次,如果所示语言使用了一种不太常见的语法,就像Python中的列表推导那样,那么一旦你意识到这只是你理解的某个概念的变体,就能更容易辨别出正在运行的是什么。前面的代码示例说明了以简单命令式编程特性编写的程序与利用多种语言中可用的函数式编程特性编写的程序之间的区别。我可以对并发编程提出类似的论点。语言(和库)已经更新换代,不必像20年前那样编写今天的并发程序了。但是为了帮助你更深刻地认识这一点,不妨回到2004年,也就是Java1.4的时代,并思考以下问题:给定两个任务,每个任务产生一个字符串,并行调用两个任务并返回产生的第一个字符串。假设类型StringComputation具有字符串生成方法compute。在Java1.4中,此问题可以通过以下方式解决(不要试图理解代码;代码很长,细节不重要):

StringfirstOf(finalStringComputationcomp1finalStringComputationcomp2)throwsInterruptedException{classResult{privateStringvalue=null;

publicsynchronizedvoidsetValue(Stringstr){if(value==null){value=str;notifyAll();}}

publicsynchronizedStringgetValue()throwsInterruptedException{while(value==null)wait();returnvalue;}}

finalResultresult=newResult();Runnabletask1=newRunnable(){publicvoidrun(){result.setValue(comp1.compute());}};Runnabletask2=newRunnable(){publicvoidrun(){result.setValue(comp2.compute());}};newThread(task1).start();newThread(task2).start();returnresult.getValue();}

此实现使用了你可能不熟悉的特性(详见本书第Ⅱ部分)。以下是需要注意的要点。●代码长约30行。●它依赖于同步方法,这是Java虚拟机(JVM)中可用的一种锁形式。●它使用wait和notifyAll方法,这些方法在JVM上实现了基本的同步机制。●它启动自己的两个线程来并行运行这两个任务。下面快进到今天的Java,并重新实现该程序:

StringfirstOf(StringComputationcomp1StringComputationcomp2Executorthreads)throwsInterruptedExceptionExecutionException{varresult=newCompletableFuturelt;Stringgt;();result.completeAsync(comp1::computethreads);result.completeAsync(comp2::computethreads);returnresult.get();}

同样,忽略细节,并看以下这几点。●代码更短。●省略了类Result。它实现了一个自己的Future形式,但现在有很多语言可以使用Future,包括Java。●没有同步方法。代码在任何地方都不依赖锁。●没有wait和notifyAll方法。相反,CompletableFuture正确而高效地实现了自己的同步。●没有显式创建线程。相反,线程以Executor的形式作为参数传递,并且可以与应用程序的其他部分共享。我想强调的是,这两种变体之间还有一个不同之处。在新代码中,两个Runnable类已消失,且已被一种奇怪的语法所取代,这种语法在Java1.4:comp1::compute中并不存在。你可能会觉得这种语法令人费解,因为compute方法似乎缺少括号。实际上,此代码不调用compute,而是将方法本身用作completeAsync的参数。它可以改为lambda表达式:comp1::compute与()_gt;comp1.compute()相同。将函数作为参数传递给函数,是函数式编程的一个基本理念(这将在本书第Ⅰ部分进行详细的探讨),编写并发代码时也经常使用。这个示例的重点是:即使仍然可以用今天的Java编写第一个版本的程序,也不应该这么做。因为很难保持多线程代码的正确性,而若要让它正确并高效,则是难上加难。相反,应该借助语言中可用的内容并有效地利用它。你是否充分利用了当前使用的编程语言?一种趋势是,编程语言正变得越来越抽象,而其特性却越来越丰富,这一转变使得许多编程任务的要求降低了。与Java1相比,Java19包含更多需要理解的概念,但使用Java19编写正确而高效的程序比使用Java1更容易。特性丰富的编程语言可能更难学习,但一旦掌握,你就会认识到它们的强大。当然,一种方案的难度很大程度上取决于各人的编程背景,而且重要的是清晰地区分;简单和;熟悉的概念。前面介绍的Java和Python程序的函数式变体并不比命令式变体更复杂,但对于某些程序员来说肯定不那么熟悉。事实上,程序员在Java或Python中从命令式变体转换到函数式变体(反之亦然)比在相同的命令式或函数式风格中从Java转换到Python(反之亦然)要更难。后一种转换主要是语法问题,而第一种转换需要范式转变。当前特性丰富的编程语言的大多数优点都聚焦于函数式编程、并发和类型它们正是本书的三个主题。一个普遍的趋势是为开发人员提供抽象,使他们可以不必编写非必要的实现细节,而不必编写的代码就是无漏洞代码。例如,jump和goto很早就被高级编程语言所抛弃,取而代之的是结构化循环。但是,许多循环本身就可以使用一组标准的高阶函数来替换。类似地,直接用线程和锁来编写并发程序可能非常具有挑战性。相反,依赖线程池、特性和其他机制,可以生成更简单的模式。在许多情况下,除非必须编写自己的哈希映射或排序方法,否则没有必要使用循环和锁:这是不必要的工作,容易出错,而且不太可能达到现有实现的性能。至于类型,其安全性(能够捕捉错误)和灵活性(不必在设计选择中受过度的约束)之间一直存在对立,这种对立通常可以由安全、灵活但复杂的类型系统来解决。本书并不是一本全面的综合指南,并未涵盖函数式和并发编程或者类型的方方面面。但是,若想在日常编程中利用现代语言构造,则需要熟悉这些特性背后的抽象概念。例如,应用函数模式比了解lambda表达式的语法更重要。本书只介绍有效使用语言特性所需的基本概念。本书所涵盖的内容非常有限,仅仅揭示了函数式和并发编程以及类型相关知识的冰山一角(Scala也是如此)。更深入的主题还有待你通过其他途径探索。选择Scala的理由如前所述,本书中的大部分代码示例都是用Scala编写的。这可能不是你最熟悉的语言,也可能不是你开发下一个应用程序时计划使用的语言。因此,你可能会很自然地问我为什么选择它而非更主流的语言。Scala是一种旨在结合面向对象编程和函数式编程的语言,同时对并发性有很好的支持。它是一种混合式语言,也称为多范式语言。事实上,之前使用Java和Python编写的随机移位程序的3个版本都可以用Scala编写:

defrandShift(nums:List[Int]rand:Random):List[Int]={valshiftedNums=List.newBuilder[Int]for(numlt;_nums){valshifted=num rand.between(_1011)if(shiftedgt;0){shiftedNums =shifted}}shiftedNums.result()}

defrandShift(nums:List[Int]rand:Random):List[Int]=nums.view.map(num=gt;num rand.between(_1011)).filter(shifted=gt;shiftedgt;0).toList

defrandShift(nums:List[Int]rand:Random):List[Int]=for{numlt;_numsshifted=num rand.between(_1011)ifshiftedgt;0}yieldshifted

第一个函数是命令式的,基于迭代和可变列表。第二个变体是函数式的,它显式地使用了map和filter。最后一个变体依赖于Scala中的for推导式,这是一种类似于Python的列表推导式(但比它更强大)的机制。还可以使用Scala编写并发问题的简洁解决方案。它用到了Future和线程池,就像前面的Java程序:

deffirstOf(comp1:StringComputationcomp2:StringComputation)(usingExecutionContext):String={valfuture1=Future(comp1.compute())valfuture2=Future(comp2.compute())Await.result(Future.firstCompletedOf(Set(future1future2))timeout)}

考虑到本书的主旨,将Scala用作代码示例的好处有以下几点。首先,这种语言特性丰富,可以在不切换语言的情况下阐释许多概念。Scala不但拥有函数式和并发编程的许多标准特性,还具有强大的类型系统。其次,Scala是最近才推出的,它设计得很精致(通常也很巧妙)。与早期的语言相比,Scala被用于讨论基础概念时没有那么多历史包袱。最后,Scala语法非常传统,大多数程序员都可以直接上手。然而,重要的是谨记本书的重点是编程语言特性,而非Scala。虽然我个人喜欢将其用作一种教学语言,但我并非在推销Scala。这也不是一本Scala的教科书。这一切皆因我恰好需要一种在我涉猎的所有领域都有简洁表现的编程语言,而我相信Scala满足以上所有要求。

目标读者本书的目标读者是有足够经验的程序员,他们不会因为简单的语法问题而分心。我假设读者具有一定的Java经验,或者有足够的整体编程经验来阅读和理解简单的Java代码。本书读者应熟悉类、方法、对象、类型、变量、循环和条件等概念。读者还应基本理解程序执行(执行堆栈、垃圾回收、异常),以及数据结构和算法。有关书中深入介绍的其他关键术语的基本定义与涉及的章节,可以参阅术语表(通过扫描封底二维码获取)。不必事先了解函数式编程或并发编程,也不必事先了解Scala。许多读者可能对函数式或并发概念(如递归或锁)有一定的了解,但这并不是必需的。例如,不要求能理解前面讨论的函数式Python和Java程序,或者两个Java并发程序,或者最后两个Scala函数。事实上,如果你认为这些程序有点奇怪和难以理解,那么本书是为你量身打造的!相比之下,数字移位程序的命令式变体应该很容易理解,我希望你能够理解所有与之对应的代码,无论它是用Java、Python,还是用Scala编写的。如果Scala的语法与其他语言的语法相似,你应该能理解简单的Scala语法,并能掌握新引入的元素。Scala的语法受到了Java语法的启发,而Java的语法又受到了C语法的启发大多数程序员都能快速适应此承接及过渡。Scala与Java的不同之处将在介绍代码示例时一一说明。现在,我只强调三点不同。●分号推理。在Scala中,终止分号是由编译器推断出来的并且很少显式使用。它们可能会偶尔出现,例如,用于将两个语句放在同一行。●不需要;return。尽管Scala中存在return关键字,但它很少被使用。相反,函数会隐式返回其主体中计算的最后一个表达式的值。●符号缩进。用于定义代码块的大括号通常可以从缩进中推断出来,并且它们是可选的。第一个ScalarandShift变体可以写成如下形式:

defrandShift(nums:List[Int]rand:Random):List[Int]=valshiftedNums=List.newBuilder[Int]fornumlt;_numsdovalshifted=num rand.between(_1011)ifshiftedgt;0thenshiftedNums =shiftedendforshiftedNums.result()endrandShift

当使用缩进来创建块时,可以添加标记来强调块结尾,但它们是任意的。randShift函数的更短版本采用以下形式:

defrandShift(nums:List[Int]rand:Random):List[Int]=valshiftedNums=List.newBuilder[Int]fornumlt;_numsdovalshifted=num rand.between(_1011)ifshiftedgt;0thenshiftedNums =shiftedshiftedNums.result()

在本书中,代码示例一般情况下依赖于缩进而不是大括号,并且为了紧凑起见省略了大多数结束标记。希望读者能够阅读这种形式的命令式Scala代码,就像前面的函数一样。如何阅读本书本书的主要价值在于它的代码示例(扫描封底二维码即可下载完整代码示例)。在很大程度上,文本仅是用来描述代码的。代码示例往往很短,并侧重于要阐释的概念。特别是,很少有示例被设计用于执行日常编程中需要解决的特定任务。这并非一本食谱。而且,本书将从头开始引入概念,从基本原理开始,并向应用程序级别进行扩展和抽象。而最具应用性的代码往往集中在各个部分的最后章节。这种安排最有助于深入理解那些可以在之后被转换成Scala之外的其他语言的特性。如果你感觉前面讲述的主题过于简单,节奏太慢,请一定要耐住性子。建议按从头至尾的顺序阅读本书。大多数章节及代码示例都是以开头几章介绍的想法和程序为基础展开的。例如,同一问题的多种解决方案通常散布在不同的章节,以阐释不同的编程语言特性集。同样,关于并发编程的第Ⅱ部分也使用了第Ⅰ部分关于函数式编程的概念。虽然不建议随机浏览本书内容,但你仍旧可以快速浏览关于熟知的特性的部分。对于那些将本书用作教材的本科生和研究生而言,只要能理解代码,便可直接进入下一部分。若觉得代码费解,就应该放慢速度,留意文本中的解释。可以通过以下方式安全地跳过某些内容。●关于类型的第15章可以被完全跳过。在本书的其他章节,几个代码示例简化了假设,以避免类型边界和类型变换之类的复杂概念。基本了解Java类型,包括泛型(但不一定要使用通配符)和多态性,就足够了。●任何补充知识(如;关于作用域)都可以被安全地忽略。你可能会发现这些补充知识都是作为参考内容而设计的,鉴于这本书的主题(我不想让你失望),而且它们可能很长,在正文中也很少被提及,这些参考性的知识都可以被忽略。●任何;案例研究章节都可以被跳过。不过,不建议你这样做,因为案例研究的代码采用了最有趣的方式来组合特性。而且所有的案例研究涉及的概念或语法全都来自前述章节而非后述章节。正文通常不会提及案例研究中的代码,只有一个小例外:10.8节提到的一个二叉搜索树的高级实现位于第8章。

新华一城书集店铺主页二维码
新华一城书集 微信公众号认证
上海新华书店官方微信书店
扫描二维码,访问我们的微信店铺
随时随地的购物、客服咨询、查询订单和物流...

函数式与并发编程

手机启动微信
扫一扫购买

收藏到微信 or 发给朋友

1. 打开微信,扫一扫左侧二维码

2. 点击右上角图标

点击右上角分享图标

3. 发送给朋友、分享到朋友圈、收藏

发送给朋友、分享到朋友圈、收藏

微信支付

支付宝

扫一扫购买

打开微信,扫一扫

或搜索微信号:xhbookmall
新华一城书集微书店官方微信公众号

收藏到微信 or 发给朋友

1. 打开微信,扫一扫左侧二维码

2. 点击右上角图标

点击右上角分享图标

3. 发送给朋友、分享到朋友圈、收藏

发送给朋友、分享到朋友圈、收藏