当前位置:首页 > 科技  > 软件

如何在函数式编程中处理可变状态和副作用?

来源: 责编: 时间:2024-01-15 09:20:12 326观看
导读函数式编程的不可变和无副作用首先函数式编程中的比较鲜明的特性就是不可变性和无副作用。可变 VS 不可变不可变性简单点说,就是不会改变已经定义的变量1.变幻莫测的对象状态在面向对象或者面向过程式的编程中,当遇到一

函数式编程的不可变和无副作用

首先函数式编程中的比较鲜明的特性就是不可变性和无副作用。MkA28资讯网——每日最新资讯28at.com

MkA28资讯网——每日最新资讯28at.com

MkA28资讯网——每日最新资讯28at.com

可变 VS 不可变

不可变性简单点说,就是不会改变已经定义的变量MkA28资讯网——每日最新资讯28at.com

1.变幻莫测的对象状态

在面向对象或者面向过程式的编程中,当遇到一些需要计算累计值的时候,我们通常会定义某个变量,再对变量的赋值不断更新,最后输出变量的最终结果。MkA28资讯网——每日最新资讯28at.com

假设需要计算班级某门课程平均分,学生分数结构如下:MkA28资讯网——每日最新资讯28at.com

class StudentScore {    public String id;    public String studentId;    public String courseId;    public String classId;    public Double score;    public StudentScore(String id, String studentId, String courseId, String classId, Double score) {        this.id = id;        this.studentId = studentId;        this.courseId = courseId;        this.classId = classId;        this.score = score;    }    public Double getScore() {        return score;    }}

在面向对象或者面向过程式的编程中,我们通常会将计算平均分的方法的实现写成下面这样:MkA28资讯网——每日最新资讯28at.com

    public Double avgScore(List<StudentScore> studentScores) {        Double sumScore = 0d;        for (StudentScore studentScore : studentScores) {            sumScore += studentScore.getScore();        }        return sumScore / studentScores.size();    }

2.函数式与不可变

在函数式编程中,某个变量被定义了之后就不会再改变。同样的计算累计值的场景,在函数式编程中则可以被定义为一连串的函数的链式调用,最后返回最终的结果。MkA28资讯网——每日最新资讯28at.com

    public Double avgScoreFP(List<StudentScore> studentScores) {        return studentScores.stream().map(StudentScore::getScore)            .reduce((d1, d2) -> (d1 + d2) / 2).orElse(0d);    }

MkA28资讯网——每日最新资讯28at.com

这么做的好处就是,代码会更加健壮可靠,对于问题的调查也会更加容易。当我们发现某个计算值有误时,在可变变量的场景中,我们就需要结合实际代码,调查变量所有引用和改动的地方。MkA28资讯网——每日最新资讯28at.com

当定义的变量都不可变时,问题只会出现在某个较小的函数的计算当中,这部分计算逻辑中。我们只需要关注函数的输入和输出就能调查出具体问题是出在函数调用链的哪个环节上。然后再针对该函数编写相应的单元测试用例,便能保证代码的稳定性。MkA28资讯网——每日最新资讯28at.com

而且链式的函数调用,每个函数都是较小的计算单元,测试用例的场景也会相对较小,编写单元测试用例时,也会加简单容易。MkA28资讯网——每日最新资讯28at.com

无副作用 VS 副作用

无副作用是指函数的实现时,不应该对入参做任何更改,并保证对系统是无影响的。这和面向对象编程是有很大差别的。MkA28资讯网——每日最新资讯28at.com

1.副作用

比如需要更新学生成绩时,面向对象编程,则可能是学生成绩类,会具有一个可以直接设置新成绩的方法来更新学生成绩。MkA28资讯网——每日最新资讯28at.com

    public void updateScore(StudentScore studentScore, Double newScore) {        studentScore.setScore(newScore);    }

MkA28资讯网——每日最新资讯28at.com

这种实现方式,无疑已经对入参 studenScore 造成了影响。如果有更复杂的逻辑,多次更新 studentScore 的 score 属性的值,那么最终,谁也无法预知原先的这个 studentScore 的最终状态是什么样子。MkA28资讯网——每日最新资讯28at.com

面向对象的最大问题,就是对象状态的不确定性。某个对象经过一连串的方法调用后,很难判断出对象的最终状态,其中如果涉及到缓存,并发等问题,问题的调查则会更加困难。MkA28资讯网——每日最新资讯28at.com

2.无副作用

在函数式编程中,则完全不同,我们需要定义一个函数,入参为原学生科目信息,和需要更改的成绩最新值,返回值则将是另一个新的学生成绩实例。MkA28资讯网——每日最新资讯28at.com

  public StudentScore updatedScoreFP(StudentScore studentScore, Double newScore) {        return new StudentScore(studentScore.id, studentScore.studentId, studentScore.courseId, studentScore.classId, newScore);    }

MkA28资讯网——每日最新资讯28at.com

而上面的这种写法,我们能够保证原先的 studentScore 是不会被更改的,这个函数无论入参怎么更换,最终的输出都是一个新的 StudentScore 对象。这个函数无论入参怎么变化,无论被调用多少次,对外部系统都是无影响的。MkA28资讯网——每日最新资讯28at.com

函数式编程所强调的无副作用,是指函数的调用不会对系统、入参造成任何函数功能以外的影响。同一个对象无论调用某个函数多少次,该对象的属性依旧不变。对象新的状态则是通过新的对象体现。这虽然会耗费一些资源,但是能使我们编写的代码更加稳定可靠。MkA28资讯网——每日最新资讯28at.com

函数式编程的语法支持

对于变量不可变性的实践,java中可以尽量在变量的定义时使用final关键字修饰。对于无副作用的实践,java中并没有专门的语法糖支持,但是JDK1.8之后的 Stream 操作( map, reduce, groupBy 等)以及相关的函数式编程相关的支持都是值得去实践的。MkA28资讯网——每日最新资讯28at.com

在Scala中对于对象的不可变性,可以通过 case class 来定义纯数据类,保证相关的数据类实例的不可变性,对于一般变量则通过 var 和 val 区分变量是否可变,一般变量尽量使用val关键字修饰以保证其不可变。无副作用的实践上,Scala中对于类对象的操作则可以封装在类的伴生对象中。当然也需要自己在开发过程中具备保证函数无副作用的意识。MkA28资讯网——每日最新资讯28at.com

上面例子的Scala 2实现如下:MkA28资讯网——每日最新资讯28at.com

package demo.basiccase class StudentScore(id: String,                        studentId: String,                        courseId: String,                        classId: String,                        score: Double) {    override def toString: String =        s"StudentScore:{id: ${id}, studentId:${studentId}, courseId:${courseId}, score: ${score}}"}object StudentScore {    def avgScore(studentScores: Array[StudentScore]): Double = {        studentScores.map[Double](s => s.score).reduce((s1, s2) => (s1 + s2) / 2)    }    def updateScore(studentScore: StudentScore, newScore: Double): StudentScore = {        StudentScore(studentScore.id, studentScore.studentId, studentScore.courseId, studentScore.classId, newScore)    }}object FunctionalProgramingDemo {    def main(args: Array[String]): Unit = {        val s1 = StudentScore("id-0001", "student-0001", "course-0001", "class-0001", 83.5)        val s2 = StudentScore("id-0002", "student-0002", "course-0001", "class-0001", 82.0)        val s3 = StudentScore("id-0002", "student-0003", "course-0001", "class-0001", 81.0)        val scores = Array(s1, s2, s3)        val avgScore = StudentScore.avgScore(scores)        println(avgScore)        val s3New = StudentScore.updateScore(s3, 79.5)        println(s3)        println(s3New)        /*        81.875        StudentScore:{id: id-0002, studentId:student-0003, courseId:course-0001, score: 81.0}        StudentScore:{id: id-0002, studentId:student-0003, courseId:course-0001, score: 79.5}        * */    }}

总结

总之函数式编程所强调的的不可变性和无副作用,能够帮助我们编写出更加稳定可靠的代码,构建更加健壮的系统。MkA28资讯网——每日最新资讯28at.com

  • 以上涉及到Java部分的代码的 GitHub 链接:https://github.com/stevenzearo/ichat/blob/master/demo/java-demo/src/main/java/basic/FunctionalProgramingDemo.java
  • 涉及到Scala部分的代码的 GitHub 链接:https://github.com/stevenzearo/scala-gradle/blob/master/src/main/scala/demo/basic/FunctionalProgramingDemo.scala

本文链接:http://www.28at.com/showinfo-26-60934-0.html如何在函数式编程中处理可变状态和副作用?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Figma 是如何做协同编辑的?

下一篇: 我们优雅判断 interface 是否为 nil

标签:
  • 热门焦点
  • 一加Ace2 Pro官宣:普及16G内存 引领24G

    一加官方今天继续为本月发布的新机一加Ace2 Pro带来预热,公布了内存方面的信息。“淘汰 8GB ,12GB 起步,16GB 普及,24GB 引领,还有呢?#一加Ace2Pro#,2023 年 8 月,敬请期待。”同时
  • vivo TWS Air开箱体验:真轻 臻好听

    在vivo S15系列新机的发布会上,vivo的最新款真无线蓝牙耳机vivo TWS Air也一同发布,本次就这款耳机新品给大家带来一个简单的分享。外包装盒上,vivo TWS Air保持了vivo自家产
  • 这款新兴工具平台,让你的电脑效率翻倍

    随着信息技术的发展,我们获取信息的渠道越来越多,但是处理信息的效率却成为一个瓶颈。于是各种工具应运而生,都在争相解决我们的工作效率问题。今天我要给大家介绍一款效率
  • 得物宠物生意「狂飙」,发力“它经济”

    作者|花花小萌主近日,得物宣布正式上线宠物鉴别,通过得物App内的&ldquo;在线鉴别&rdquo;,可找到鉴别宠物的选项。通过上传自家宠物的部位细节,就能收获拥有专业资质认证的得物鉴
  • 阿里瓴羊One推出背后,零售企业迎数字化新解

    作者:刘旷近年来随着数字经济的高速发展,各式各样的SaaS应用服务更是层出不穷,但本质上SaaS大多局限于单一业务流层面,对用户核心关切的增长问题等则没有提供更好的解法。在Saa
  • 国行版三星Galaxy Z Fold5/Z Flip5发布 售价7499元起

    2023年8月3日,三星电子举行Galaxy新品中国发布会,正式在国内推出了新一代折叠屏智能手机三星Galaxy Z Fold5与Galaxy Z Flip5,以及三星Galaxy Tab S9
  • iQOO 11S评测:行业唯一的200W标准版旗舰

    【Techweb评测】去年底,iQOO推出了“电竞旗舰”iQOO 11系列,作为一款性能强机,该机不仅全球首发2K 144Hz E6全感屏,搭载了第二代骁龙8平台及144Hz电竞
  • 电博会与软博会实现"线下+云端"的双线融合

    在本次“电博会”与“软博会”双展会利好条件的加持下,既可以发挥展会拉动人流、信息流、资金流实现快速交互流动的作用,继而推动区域经济良性发展;又可以聚
  • 亲历马斯克血洗Twitter,硅谷的苦日子在后头

    文/刘哲铭  编辑/李薇  马斯克再次挥下裁员大刀。  美国时间11月14日,Twitter约4400名外包员工遭解雇,此次被解雇的员工的主要工作为内容审核等。此前,T
Top