日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

如何在函數(shù)式編程中處理可變狀態(tài)和副作用?

來源: 責(zé)編: 時(shí)間:2024-01-15 09:20:12 198觀看
導(dǎo)讀函數(shù)式編程的不可變和無副作用首先函數(shù)式編程中的比較鮮明的特性就是不可變性和無副作用。可變 VS 不可變不可變性簡(jiǎn)單點(diǎn)說,就是不會(huì)改變已經(jīng)定義的變量1.變幻莫測(cè)的對(duì)象狀態(tài)在面向?qū)ο蠡蛘呙嫦蜻^程式的編程中,當(dāng)遇到一

函數(shù)式編程的不可變和無副作用

首先函數(shù)式編程中的比較鮮明的特性就是不可變性和無副作用。krq28資訊網(wǎng)——每日最新資訊28at.com

krq28資訊網(wǎng)——每日最新資訊28at.com

krq28資訊網(wǎng)——每日最新資訊28at.com

可變 VS 不可變

不可變性簡(jiǎn)單點(diǎn)說,就是不會(huì)改變已經(jīng)定義的變量krq28資訊網(wǎng)——每日最新資訊28at.com

1.變幻莫測(cè)的對(duì)象狀態(tài)

在面向?qū)ο蠡蛘呙嫦蜻^程式的編程中,當(dāng)遇到一些需要計(jì)算累計(jì)值的時(shí)候,我們通常會(huì)定義某個(gè)變量,再對(duì)變量的賦值不斷更新,最后輸出變量的最終結(jié)果。krq28資訊網(wǎng)——每日最新資訊28at.com

假設(shè)需要計(jì)算班級(jí)某門課程平均分,學(xué)生分?jǐn)?shù)結(jié)構(gòu)如下:krq28資訊網(wǎng)——每日最新資訊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;    }}

在面向?qū)ο蠡蛘呙嫦蜻^程式的編程中,我們通常會(huì)將計(jì)算平均分的方法的實(shí)現(xiàn)寫成下面這樣:krq28資訊網(wǎng)——每日最新資訊28at.com

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

2.函數(shù)式與不可變

在函數(shù)式編程中,某個(gè)變量被定義了之后就不會(huì)再改變。同樣的計(jì)算累計(jì)值的場(chǎng)景,在函數(shù)式編程中則可以被定義為一連串的函數(shù)的鏈?zhǔn)秸{(diào)用,最后返回最終的結(jié)果。krq28資訊網(wǎng)——每日最新資訊28at.com

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

krq28資訊網(wǎng)——每日最新資訊28at.com

這么做的好處就是,代碼會(huì)更加健壯可靠,對(duì)于問題的調(diào)查也會(huì)更加容易。當(dāng)我們發(fā)現(xiàn)某個(gè)計(jì)算值有誤時(shí),在可變變量的場(chǎng)景中,我們就需要結(jié)合實(shí)際代碼,調(diào)查變量所有引用和改動(dòng)的地方。krq28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)定義的變量都不可變時(shí),問題只會(huì)出現(xiàn)在某個(gè)較小的函數(shù)的計(jì)算當(dāng)中,這部分計(jì)算邏輯中。我們只需要關(guān)注函數(shù)的輸入和輸出就能調(diào)查出具體問題是出在函數(shù)調(diào)用鏈的哪個(gè)環(huán)節(jié)上。然后再針對(duì)該函數(shù)編寫相應(yīng)的單元測(cè)試用例,便能保證代碼的穩(wěn)定性。krq28資訊網(wǎng)——每日最新資訊28at.com

而且鏈?zhǔn)降暮瘮?shù)調(diào)用,每個(gè)函數(shù)都是較小的計(jì)算單元,測(cè)試用例的場(chǎng)景也會(huì)相對(duì)較小,編寫單元測(cè)試用例時(shí),也會(huì)加簡(jiǎn)單容易。krq28資訊網(wǎng)——每日最新資訊28at.com

無副作用 VS 副作用

無副作用是指函數(shù)的實(shí)現(xiàn)時(shí),不應(yīng)該對(duì)入?yún)⒆鋈魏胃模⒈WC對(duì)系統(tǒng)是無影響的。這和面向?qū)ο缶幊淌怯泻艽蟛顒e的。krq28資訊網(wǎng)——每日最新資訊28at.com

1.副作用

比如需要更新學(xué)生成績(jī)時(shí),面向?qū)ο缶幊蹋瑒t可能是學(xué)生成績(jī)類,會(huì)具有一個(gè)可以直接設(shè)置新成績(jī)的方法來更新學(xué)生成績(jī)。krq28資訊網(wǎng)——每日最新資訊28at.com

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

krq28資訊網(wǎng)——每日最新資訊28at.com

這種實(shí)現(xiàn)方式,無疑已經(jīng)對(duì)入?yún)?nbsp;studenScore 造成了影響。如果有更復(fù)雜的邏輯,多次更新 studentScore 的 score 屬性的值,那么最終,誰也無法預(yù)知原先的這個(gè) studentScore 的最終狀態(tài)是什么樣子。krq28資訊網(wǎng)——每日最新資訊28at.com

面向?qū)ο蟮淖畲髥栴},就是對(duì)象狀態(tài)的不確定性。某個(gè)對(duì)象經(jīng)過一連串的方法調(diào)用后,很難判斷出對(duì)象的最終狀態(tài),其中如果涉及到緩存,并發(fā)等問題,問題的調(diào)查則會(huì)更加困難。krq28資訊網(wǎng)——每日最新資訊28at.com

2.無副作用

在函數(shù)式編程中,則完全不同,我們需要定義一個(gè)函數(shù),入?yún)樵瓕W(xué)生科目信息,和需要更改的成績(jī)最新值,返回值則將是另一個(gè)新的學(xué)生成績(jī)實(shí)例。krq28資訊網(wǎng)——每日最新資訊28at.com

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

krq28資訊網(wǎng)——每日最新資訊28at.com

而上面的這種寫法,我們能夠保證原先的 studentScore 是不會(huì)被更改的,這個(gè)函數(shù)無論入?yún)⒃趺锤鼡Q,最終的輸出都是一個(gè)新的 StudentScore 對(duì)象。這個(gè)函數(shù)無論入?yún)⒃趺醋兓瑹o論被調(diào)用多少次,對(duì)外部系統(tǒng)都是無影響的。krq28資訊網(wǎng)——每日最新資訊28at.com

函數(shù)式編程所強(qiáng)調(diào)的無副作用,是指函數(shù)的調(diào)用不會(huì)對(duì)系統(tǒng)、入?yún)⒃斐扇魏魏瘮?shù)功能以外的影響。同一個(gè)對(duì)象無論調(diào)用某個(gè)函數(shù)多少次,該對(duì)象的屬性依舊不變。對(duì)象新的狀態(tài)則是通過新的對(duì)象體現(xiàn)。這雖然會(huì)耗費(fèi)一些資源,但是能使我們編寫的代碼更加穩(wěn)定可靠。krq28資訊網(wǎng)——每日最新資訊28at.com

函數(shù)式編程的語法支持

對(duì)于變量不可變性的實(shí)踐,java中可以盡量在變量的定義時(shí)使用final關(guān)鍵字修飾。對(duì)于無副作用的實(shí)踐,java中并沒有專門的語法糖支持,但是JDK1.8之后的 Stream 操作( map, reduce, groupBy 等)以及相關(guān)的函數(shù)式編程相關(guān)的支持都是值得去實(shí)踐的。krq28資訊網(wǎng)——每日最新資訊28at.com

在Scala中對(duì)于對(duì)象的不可變性,可以通過 case class 來定義純數(shù)據(jù)類,保證相關(guān)的數(shù)據(jù)類實(shí)例的不可變性,對(duì)于一般變量則通過 var 和 val 區(qū)分變量是否可變,一般變量盡量使用val關(guān)鍵字修飾以保證其不可變。無副作用的實(shí)踐上,Scala中對(duì)于類對(duì)象的操作則可以封裝在類的伴生對(duì)象中。當(dāng)然也需要自己在開發(fā)過程中具備保證函數(shù)無副作用的意識(shí)。krq28資訊網(wǎng)——每日最新資訊28at.com

上面例子的Scala 2實(shí)現(xiàn)如下:krq28資訊網(wǎng)——每日最新資訊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}        * */    }}

總結(jié)

總之函數(shù)式編程所強(qiáng)調(diào)的的不可變性和無副作用,能夠幫助我們編寫出更加穩(wěn)定可靠的代碼,構(gòu)建更加健壯的系統(tǒng)。krq28資訊網(wǎng)——每日最新資訊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.www897cc.com/showinfo-26-60934-0.html如何在函數(shù)式編程中處理可變狀態(tài)和副作用?

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: Figma 是如何做協(xié)同編輯的?

下一篇: 我們優(yōu)雅判斷 interface 是否為 nil

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 揭阳市| 五寨县| 射阳县| 江川县| 高州市| 平陆县| 仲巴县| 白水县| 宣汉县| 建湖县| 柳河县| 巴彦县| 黑河市| 桑日县| 老河口市| 绥化市| 桂阳县| 木里| 鄄城县| 宕昌县| 绩溪县| 和田市| 瑞金市| 浏阳市| 罗江县| 敦化市| 隆回县| 高阳县| 安庆市| 海阳市| 蓬莱市| 汤原县| 昆山市| 绍兴市| 辽中县| 阿荣旗| 屏山县| 图木舒克市| 保山市| 芮城县| 宁化县|