红帽白皮书新鲜出炉!点击获取,让你的云战略更胜一筹! 了解详情
写点什么

反对 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:466160
用户头像

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

关注

评论

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

Apache Paimon 在同程旅行的探索实践

Apache Flink

大数据 flink 实时计算

深入探索Go语言的unsafe包,揭秘它的黑科技和应用场景!

王中阳Go

golang 高效工作 面试题 黑科技 Go 语言

物联网核心套件IoTCore:设备状态数据存储到时序数据库TSDB

百度开发者中心

物联网

深度学习基础入门篇[二]:机器学习常用评估指标:AUC、mAP、IS、FID、Perplexity、BLEU、ROUGE等详解 1.基础指

汀丶人工智能

人工智能 机器学习 深度学习 算法评价指标

从逻辑到硬件:如何转换PCB布局?

华秋PCB

工具 电路 PCB PCB布局 PCB设计

【干货】验证码的常见类型总结

宙哈哈

php html 验证码 短信验证码

局域网IP扫描软件:IP Scanner Pro激活版

真大的脸盆

Mac IP 局域网管理 IP扫描工具 局域网扫描

目前led显示屏厂家存在的问题

Dylan

制造 行业 LED显示屏

阿里工作10年,我总结出了这份1071页Spring全家桶核心笔记

三十而立

Flink SQL 在美团实时数仓中的增强与实践

Apache Flink

大数据 flink 实时计算

autodesk maya 2023最新中文版 Maya动画和建模软件

魔仙苹果mac堡

Autodesk Maya maya破解版 玛雅2023下载

从Spring的AOP看Synchronized锁失效和事务失效的情况

做梦都在改BUG

建木在 Rainbond 上使用实践

北京好雨科技有限公司

云原生 CI/CD #Kubernetes# rainbond 企业号 4 月 PK 榜

Autodesk AutoCAD 2024 Mac(cad2024) v2024.3 支持M1 兼容Mac13系统

魔仙苹果mac堡

mac软件下载 M1芯片 cad2024激活版 Autodesk AutoCAD

Excelize 入选 2022 中国开源创新大赛优秀项目

xuri

golang 开源 Go 语言 Excelize OOXML

JetBrains CLion 2023中文版安装教程CLion 2023新功能

魔仙苹果mac堡

C/C++ CLion 2023 JetBrains CLion破解版

基于 Nginx&Lua 实现自建服务端埋点系统

亚马逊云科技 (Amazon Web Services)

Amazon

2023 年金三银四最新版 Java 面试八股文教程,涵盖 25 大专题:Java 基础 +spring 全家桶 + 大数据 + 网络 + 设计模式 + 算法

三十而立

一文快速了解火山引擎A/B测试平台

字节跳动数据平台

大数据 AB testing实战 A/B 测试 企业号 4 月 PK 榜

基于 Flink ML 搭建的智能运维算法服务及应用

Apache Flink

大数据 flink 实时计算

2023年成都.NET线下技术沙龙来了!大咖分享,报名从速

MASA技术团队

.net dapr MASA

从零学习SDK(2)SDK的基本概念和组成部分

MobTech袤博科技

2023Java岗面试,进互联网大厂必备Java面试八股文真题解析

程序知音

Java java面试 后端技术 八股文 Java面试八股文

AI开发实践:关于停车场中车辆识别与跟踪

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号 4 月 PK 榜 车辆检测

LeetCode题解:136. 只出现一次的数字,哈希表,JavaScript,详细注释

Lee Chen

JavaScript LeetCode

远程调试为何要亲历现场,也许也可以这样解决

石臻臻的杂货铺

远程调试

长安信托:拥抱数字信托,探索多项目管理新路径

万事ONES

Higress GitHub star 突破 1k,来自社区开发者和用户的寄语

阿里巴巴云原生

阿里云 云原生 Higress

恶意爬虫?能让恶意爬虫遁于无形的小Tips

宙哈哈

Python html nginx 爬虫

解决Parallels Desktop 18.2.0提示“由于临界误差,不能启动虚拟机”的问题

魔仙苹果mac堡

Parallels Desktop 18 pd18虚拟机 PD虚拟机不能联网

关于验证码,你不知道的一些问题!

宙哈哈

php html 记录 验证码

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