最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

反对 for 行动

  • 2009-07-13
  • 本文字数:2089 字

    阅读完需:约 7 分钟

Francesco Cirillo 于不久前发起了“反对if 行动”,受此影响,Matthew Podwysocki 也用这种方式提出了自己的声明,即“反对for 行动”。

Matthew Poswysocki 生活在华盛顿特区,作为微软的高级咨询师,维护或参与了诸多社区活动(如 DC ALT.NET 讨论组),并致力于推广各种敏捷实践。这次他提出,在代码中应该尽量使用和构建可以进行组合的函数,而不是显式的循环语句(包括 for、foreach 和 while)。

Matthew 认为,通过循环来实现的功能往往可以分为以下三种情况:

  1. 查询(映射、过滤等等)
  2. 聚合(求和、计数等等)
  3. 进行一些有副作用(Side Effect)的操作(读取文件、发送消息等等)

Matthew 看来,使用 for 循环来处理“查询”和“聚合”时,最大的问题在于将关注点放在了如何做(How)而不是做什么(What)。他举了一个例子,“找出 100 以内所有质数”,并给出了一个实现:

复制代码
<span>var</span><span> numbers </span><span>=</span><span> Enumerable.Range(</span><span>1</span><span>, </span><span>100</span><span>);
</span><span>var</span><span> output </span><span>=</span> <span>new</span><span> List</span><span><</span><span>int</span><span>></span><span>();
</span><span>foreach</span><span>(</span><span>var</span><span> number </span><span>in</span><span> numbers)
</span><span>if</span><span>(IsPrime(number)) output.Add(number);</span>

Matthew 认为:

这里的问题在于我们很难将现有逻辑与另一个操作进行组合,因为这里的实现涉及了“怎么做”。我们应该使用.NET 2.0 以上版本中的泛型及延迟加载的特性进行函数式的构造。这样可以带来“声明式(declarative)”的感觉,而关注点就只有“做什么”了:

复制代码
<span>var</span><span> primes </span><span>=</span><span> Enumerable.Range(</span><span>1</span><span>, </span><span>100</span><span>)
.Where(x </span><span>=></span><span> IsPrime(x));</span>

Matthew 提出,应该尽量避免在一个循环中进行多种操作,这样会为代码的可读性和维护性带来负面影响。而在 Martin Fowler 的 Refactoring 站点中,拆分循环内部逻辑的重构方式被命名为“ Split Loop ”。Matthew 认为较好的方式是将逻辑进行组合,例如求出“100 以内质数的数量”便可以这样实现:

复制代码
<span>var</span><span> primesCount </span><span>=</span><span> Enumerable.Range(</span><span>1</span><span>, </span><span>100</span><span>)
.Where(x </span><span>=></span><span> IsPrime(x))
.Count();</span>

对于产生副作用的情况,Matthew 引用了 Eric Lippert对于“为什么IEnumerable没有ForEach 扩展方法”的回应。Eric 认为,引入IEnumerable的ForEach 扩展方法事实上带来了副作用,而违背了IEnumerable的设计初衷。此外,ForEach 还会形成闭包,可能会造成一些难以发现的引用问题。

Matthew 并没有赞同这种说法,不过它对这个看法表示理解。他认为,如果是使用 C#进行编程,使用 foreach 来遍历一个 IEnumerable 没有太大问题。不过在 F#中,最好还是使用 iter 或 iteri 方法进行遍历。关于这点,他使用 F#交互命令行进行了演示:

复制代码
<span>></span> <span>let</span><span> flip f y x </span><span>=</span><span> f x y
</span><span>-</span><span> [</span><span>1</span><span>..</span><span>10</span><span>]
</span><span>-</span> <span>|></span><span> List.map((</span><span>*</span><span>) </span><span>2</span><span>)
</span><span>-</span> <span>|></span><span> List.filter(flip (</span><span>%</span><span>) </span><span>3</span> <span>>></span><span> (</span><span>=</span><span>) </span><span>0</span><span>)
</span><span>-</span> <span>|></span><span> List.iter(printfn </span><span>"</span><span>%d</span><span>"</span><span>);;
</span><span>6</span>
<span>12</span>
<span>18</span>
<span>></span><span> [</span><span>1</span><span>..</span><span>10</span><span>]
</span><span>-</span> <span>|></span><span> List.map((</span><span>*</span><span>) </span><span>2</span><span>)
</span><span>-</span> <span>|></span><span> List.filter(flip (</span><span>%</span><span>) </span><span>3</span> <span>>></span><span> (</span><span>=</span><span>) </span><span>0</span><span>)
</span><span>-</span> <span>|></span><span> List.iteri(printfn </span><span>"</span><span>%d\t%d</span><span>"</span><span>);;
</span><span>0</span> <span>6</span>
<span>1</span> <span>12</span>
<span>2</span> <span>18</span>

社区中有人认为,这个行动的目的是希望在面向对象编程环境中融入部分函数式编程的理念。C# 3.0 引入了 Lambda 表达式,将高阶函数在.NET 中的应用切实地推广开来。同时,其他平台也在进行着类似的改变。例如最近颇受好评的 Scala 语言也引入了函数式编程特性。

你对 for 的使用有何看法,并且对函数式编程的看法如何?

2009-07-13 20:466170
用户头像

发布了 157 篇内容, 共 52.6 次阅读, 收获喜欢 6 次。

关注

评论

发布
暂无评论
发现更多内容

TDD之让我们再聊聊TDD

刘冉

TDD

博文|Apache Pulsar 在自研数据管道中的技术实践

Apache Pulsar

大数据 分布式 云原生 中间件 Apache Pulsar 消息系统

KoP 2.8.0 新特性前瞻(内附视频)

Apache Pulsar

kafka 架构 分布式 Apache Pulsar KoP 2.8.0

javaScript基础篇说一说循环应该怎么用

你好bk

JavaScript 大前端 ES6 html/css

数据校验

卢卡多多

参数校验 11月日更

测试策略实践之分类漫谈

刘冉

CSS页面设计稿构思与实现(五)之border-radius

Augus

CSS 11月日更

linux检测系统是否被入侵(下)

入门小站

Linux

Lua-复合变量

Changing Lin

11月日更

测试策略实践之测试自动化与自动化测试

刘冉

测试管理 测试策略

告别晦涩难懂的物理,《张朝阳的物理课》了解一下

脑极体

🔄 这些JS数组遍历是否都用过 🔄

空城机

JavaScript 大前端 11月日更

进击的Java(五)

ES_her0

11月日更

质量基础设施一站式服务平台方案,NQI一站式公共平台开发

电微13828808271

TDD之让我们再聊聊TDD(终)--正其思,规其行

刘冉

TDD

2022 年 9 个最佳 JavaScript IDE 和代码编辑器

devpoint

JavaScript vscode IntelliJ IDEA 11月日更

TDD之让我们再聊聊TDD(续)

刘冉

TDD

测试策略实践之序篇-软件缺陷,测试计划和测试架构

刘冉

测试计划 测试策略 测试架构

13 K8S之Pod资源操作

穿过生命散发芬芳

k8s 11月日更

一场大戏!央行数字人民币被“点燃”!

CECBC

敏捷开发:川中校友登记小程序解决方案

CC同学

周边生态 | StreamNative 宣布开源 AWS SQS Connector

Apache Pulsar

开源 云原生 消息中间件 AWS SQS Connector 周边生态

架构训练营 - 模块 3 作业

焦龙

架构实战营

和12岁小同志搞创客开发:手撕代码,做一款人体感应灯

不脱发的程序猿

少儿编程 DIY 智能硬件 创客开发 Arduino

springboot整合pagehelper

小鲍侃java

11月日更

在线文本转拼音工具

入门小站

工具

区块链在营销方面的应用探索

石云升

区块链 区块链应用 11月日更

.NET6新东西--Random.Shared

喵叔

11月日更

外包学生管理系统架构文档

zjluoyue

mongoDB 简单的索引类型

liuzhen007

11月日更

学生管理系统详细架构文档练习

御道而行

架构实战营

反对for行动_研发效能_赵劼_InfoQ精选文章