软件设计之美
郑晔
开源项目 Moco 作者
19890 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 42 讲
软件设计之美
15
15
1.0x
00:00/00:00
登录|注册

19 | 函数式编程之不变性:怎样保证我的代码不会被别人破坏?

你好!我是郑晔。
经过前两讲的介绍,你已经认识到了函数式编程的能力,函数以及函数之间的组合很好地体现出了函数式编程的巧妙之处。不过,我们在讲编程范式时说过,学习编程范式不仅要看它提供了什么,还要看它约束了什么。这一讲,我们就来看看函数式编程对我们施加的约束。
在软件开发中,有一类 Bug 是很让人头疼的,就是你的代码怎么看都没问题,可是运行起来就是出问题了。我曾经就遇到过这样的麻烦,有一次我用 C 写了一个程序,怎么运行都不对。我翻来覆去地看自己的代码,看了很多遍都没发现问题,不得已,只能一步一步跟踪代码。最后,我发现我的代码调用到一个程序库时,出现了与预期不符的结果。
这个程序库是其他人封装的,我只是拿过来用。按理说,我调用的这个函数逻辑也不是特别复杂,不应该出现什么问题。不过,为了更快定位问题,我还是打开了这个程序库的源代码。经过一番挖掘,我发现在这个函数底层实现中,出现了一个全局变量。
分析之后,我发现正是这个全局变量引起了这场麻烦,因为在我的代码执行过程中,有别的程序会调用另外的函数,修改这个全局变量的值,最终,导致了我的程序执行失败。从表面上看,我调用的这个函数和另外那个函数八竿子都打不到,但是,它们却通过一个底层的全局变量,产生了相互的影响。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

函数式编程的不变性是如何保证代码不被破坏的?本文通过讲述全局变量引发的Bug案例,以及在多线程环境下的问题,阐述了可变变量带来的风险。作者以SimpleDateFormat为例,说明了共享对象可能导致的问题,并提出了在函数式编程中几乎不存在这类问题的观点。文章强调了函数式编程的不变性,通过示例展示了如何避免可变变量带来的风险,为读者解释了函数式编程的优势。 函数式编程的不变性主要体现在值和纯函数上。值是一个初始化之后就不再改变的量,而纯函数是对于相同的输入给出相同的输出且没有副作用的函数。这种不变性保证了在函数式编程中,计算天然就是不变的。这与传统编程方式有着很大的区别,因为传统方式的基础是面向内存单元的,而函数式编程则强调不变性,避免了可变变量带来的问题。 在实际应用中,可以通过编写不变类和纯函数来应用不变性。不变类的字段只在构造函数中初始化,所有方法都是纯函数,如果需要有改变,返回一个新的对象,而不是修改已有字段。另外,使用语法中不变的修饰符,如Java的final和C/C++的const,也能帮助编程者从不变的角度思考问题。 通过理解不变性,编程者可以发现之前的很多编程习惯是极其糟糕的,而将大多数代码写成不变的可以减少后期维护的成本。不变性的优势也在一些新的程序设计语言中得到体现,如Rust和Java的值类型引入。不变性是减少程序问题的一个重要努力方向,也是函数式编程的重要特点。 总的来说,本文通过讲述全局变量和多线程环境下的问题,阐述了可变变量带来的风险,并强调了函数式编程的不变性。通过介绍不变性的概念和应用,文章为读者解释了函数式编程的优势,提供了一种新的编程思路。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《软件设计之美》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(19)

  • 最新
  • 精选
  • Medusa
    如果每个函数都使用局部变量,那有些函数入参就会很多,这又与代码整洁之道里谈到函数入参尽可能少的原则对立,怎么去做一个平衡?

    作者回复: 首先,参数的多少与是否使用局部变量无关。其次,参数如果多,可以封装成类。

    2020-07-21
    11
  • sam
    初始化后不会改变的“值”就是常量吗?

    作者回复: 常量一般是预先确定的,而值是在运行过程中生成的。

    2020-07-08
    11
  • 阳仔
    变化是软件开发的永恒主题,所以在编码实践上尽量的编写不变的纯函数和类,将变化的粒度控制到最小

    作者回复: 变化是需求层面的不得已,不变是代码层面的努力控制。

    2020-07-08
    2
    8
  • 阿姆斯壮
    学习函数式编程后,昨天发生了一件事。令我很有成就感。如果按照之前工作的方法,其实就是把JavaScript当成C语言来使用。需要引入大数组的方式来记录相应关键信息。而且中间还需要考虑各种复杂的记录和查找的代码。我用来闭包的方法,引入一个变量。调整了一下代码的结构。改动不到3行。就成功解决了这个新需求。重点是获得了很大的正向反馈。现在每天下班前回看自己今天写的代码。有种隐约发现可以从函数中反应出业务的流程。不过,由于校长介绍的知识太吸引人了。这几天老是想学习DDD。但以终为始的方式实践下来却让我感觉能在工作中应用起来的知识才是目前自己最为急需的。而且能让自己进步更快。所以我重新调整了一下自己目标。先继续打磨函数式编程。争取未来半年能在公司教其他同事。另外就是引入测试的实践。这个过程中可以不断学习设计原则。在代码中思考原则如何应用。打通这些之后,才把重点引入DDD。

    作者回复: 恭喜你通过实战有所收获

    2021-08-27
    5
  • Feng
    Event Sourcing,把对象的状态每次变化抽象成独立的事件进行保存,对象的状态变化可由一系列事件的调用重现。 编写不变类,无可变化的状态;Event Sourcing记录每一次状态变化。

    作者回复: 非常好的补充。

    2020-11-04
    2
    4
  • podric
    您好,郑老师!较多地使用“不变类”是否会 + 增加内存的占用 (改变后的值和旧值同时在内存中) -> 可能由GC机制管理,因此可以解决。 + 导致运算速度的降低 (较多的复制操作)

    作者回复: 这取决于所用的语言内存管理机制是什么样的,Rust就不用考虑这样的问题。 设计首先要考虑的是模型关系,实现是下一步的考量。如果你的设计里面,这个不变的设计要经常变,那你考虑的是这个设计是不是有问题。

    2021-05-20
    2
  • 从effect java中学到了builder模式;之前实验ddd的时候就考虑了不变性;比如修改用户信息;业务逻辑提取入参数据,返回值是通过builder构造一个新的对象;builder中有完整性校验;这样我可以保证经过业务逻辑处理后返回的对象一定是一个新的并且是符合业务完整性的领域对象。

    作者回复: 设计模式是值得专门学一下的。

    2020-08-31
    2
    2
  • 独孤九剑
    函数式编程的“不变性”也是OCP原则的一种体现吧?

    作者回复: 殊途同归

    2021-07-14
    1
  • 老师,函数式语言,应用领域主要在哪里啊,适合做业务系统吗

    作者回复: 现在纯函数式的语言使用范围并不广,但越来越多的语言支持了函数式编程,比如,Java。 显然,我这里给出的例子都是在真实项目中如何使用的例子,所以,用函数式编程做业务系统不是问题。

    2020-09-12
    1
  • Janenesome
    实际生产中也有遇到过 static 全局变量带来的并发问题,而且还挺隐晦的,我们是 tomcat 容器多线程下引起的。因为代码里没有显式使用多线程,导致一开始还没意识到是什么问题。 static 用起来倒是挺方便的,因为很多时候都不会意识到会有什么问题,还是见得少了。看完《10X程序员》之后就已经下意识地少用 static 了。

    作者回复: 学到一点,用起来都是好的。

    2020-10-22
    2
收起评论
显示
设置
留言
19
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部