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

當前位置:首頁 > 科技  > 軟件

如何在函數式編程中處理可變狀態和副作用?

來源: 責編: 時間:2024-01-15 09:20:12 223觀看
導讀函數式編程的不可變和無副作用首先函數式編程中的比較鮮明的特性就是不可變性和無副作用。可變 VS 不可變不可變性簡單點說,就是不會改變已經定義的變量1.變幻莫測的對象狀態在面向對象或者面向過程式的編程中,當遇到一

函數式編程的不可變和無副作用

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

kDH28資訊網——每日最新資訊28at.com

kDH28資訊網——每日最新資訊28at.com

可變 VS 不可變

不可變性簡單點說,就是不會改變已經定義的變量kDH28資訊網——每日最新資訊28at.com

1.變幻莫測的對象狀態

在面向對象或者面向過程式的編程中,當遇到一些需要計算累計值的時候,我們通常會定義某個變量,再對變量的賦值不斷更新,最后輸出變量的最終結果。kDH28資訊網——每日最新資訊28at.com

假設需要計算班級某門課程平均分,學生分數結構如下:kDH28資訊網——每日最新資訊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;    }}

在面向對象或者面向過程式的編程中,我們通常會將計算平均分的方法的實現寫成下面這樣:kDH28資訊網——每日最新資訊28at.com

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

2.函數式與不可變

在函數式編程中,某個變量被定義了之后就不會再改變。同樣的計算累計值的場景,在函數式編程中則可以被定義為一連串的函數的鏈式調用,最后返回最終的結果。kDH28資訊網——每日最新資訊28at.com

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

kDH28資訊網——每日最新資訊28at.com

這么做的好處就是,代碼會更加健壯可靠,對于問題的調查也會更加容易。當我們發現某個計算值有誤時,在可變變量的場景中,我們就需要結合實際代碼,調查變量所有引用和改動的地方。kDH28資訊網——每日最新資訊28at.com

當定義的變量都不可變時,問題只會出現在某個較小的函數的計算當中,這部分計算邏輯中。我們只需要關注函數的輸入和輸出就能調查出具體問題是出在函數調用鏈的哪個環節上。然后再針對該函數編寫相應的單元測試用例,便能保證代碼的穩定性。kDH28資訊網——每日最新資訊28at.com

而且鏈式的函數調用,每個函數都是較小的計算單元,測試用例的場景也會相對較小,編寫單元測試用例時,也會加簡單容易。kDH28資訊網——每日最新資訊28at.com

無副作用 VS 副作用

無副作用是指函數的實現時,不應該對入參做任何更改,并保證對系統是無影響的。這和面向對象編程是有很大差別的。kDH28資訊網——每日最新資訊28at.com

1.副作用

比如需要更新學生成績時,面向對象編程,則可能是學生成績類,會具有一個可以直接設置新成績的方法來更新學生成績。kDH28資訊網——每日最新資訊28at.com

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

kDH28資訊網——每日最新資訊28at.com

這種實現方式,無疑已經對入參 studenScore 造成了影響。如果有更復雜的邏輯,多次更新 studentScore 的 score 屬性的值,那么最終,誰也無法預知原先的這個 studentScore 的最終狀態是什么樣子。kDH28資訊網——每日最新資訊28at.com

面向對象的最大問題,就是對象狀態的不確定性。某個對象經過一連串的方法調用后,很難判斷出對象的最終狀態,其中如果涉及到緩存,并發等問題,問題的調查則會更加困難。kDH28資訊網——每日最新資訊28at.com

2.無副作用

在函數式編程中,則完全不同,我們需要定義一個函數,入參為原學生科目信息,和需要更改的成績最新值,返回值則將是另一個新的學生成績實例。kDH28資訊網——每日最新資訊28at.com

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

kDH28資訊網——每日最新資訊28at.com

而上面的這種寫法,我們能夠保證原先的 studentScore 是不會被更改的,這個函數無論入參怎么更換,最終的輸出都是一個新的 StudentScore 對象。這個函數無論入參怎么變化,無論被調用多少次,對外部系統都是無影響的。kDH28資訊網——每日最新資訊28at.com

函數式編程所強調的無副作用,是指函數的調用不會對系統、入參造成任何函數功能以外的影響。同一個對象無論調用某個函數多少次,該對象的屬性依舊不變。對象新的狀態則是通過新的對象體現。這雖然會耗費一些資源,但是能使我們編寫的代碼更加穩定可靠。kDH28資訊網——每日最新資訊28at.com

函數式編程的語法支持

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

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

上面例子的Scala 2實現如下:kDH28資訊網——每日最新資訊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}        * */    }}

總結

總之函數式編程所強調的的不可變性和無副作用,能夠幫助我們編寫出更加穩定可靠的代碼,構建更加健壯的系統。kDH28資訊網——每日最新資訊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如何在函數式編程中處理可變狀態和副作用?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Figma 是如何做協同編輯的?

下一篇: 我們優雅判斷 interface 是否為 nil

標簽:
  • 熱門焦點
  • Find N3入網:最高支持16+1TB

    OPPO將于近期登場的Find N3折疊屏目前已經正式入網,型號為PHN110。本次Find N3在外觀方面相比前兩代有很大的變化,不再是小號的橫向折疊屏,而是跟別的廠商一樣采用了較為常見的
  • K60 Pro官方停產 第三方瞬間漲價

    雖然沒有官方宣布,但Redmi的一些高管也已經透露了,Redmi K60 Pro已經停產且不會補貨,這一切都是為了即將到來的K60 Ultra鋪路,屬于廠家的正常操作。但有意思的是該機在停產之后
  • 對標蘋果的靈動島 華為帶來實況窗功能

    繼蘋果的靈動島之后,華為也在今天正式推出了“實況窗”功能。據今天鴻蒙OS 4.0的現場演示顯示,華為的實況窗可以更高效的展現出實時通知,比如鎖屏上就能看到外賣、打車、銀行
  • 學習JavaScript的10個理由...

    作者 | Simplilearn編譯 | 王瑞平當你決心學習一門語言的時候,很難選擇到底應該學習哪一門,常用的語言有Python、Java、JavaScript、C/CPP、PHP、Swift、C#、Ruby、Objective-
  • 虛擬鍵盤 API 的妙用

    你是否在遇到過這樣的問題:移動設備上有一個固定元素,當激活虛擬鍵盤時,該元素被隱藏在了鍵盤下方?多年來,這一直是 Web 上的默認行為,在本文中,我們將探討這個問題、為什么會發生
  • 自律,給不了Keep自由!

    來源 | 互聯網品牌官作者 | 李大為編排 | 又耳 審核 | 谷曉輝自律能不能給用戶自由暫時不好說,但大概率不能給Keep自由。近日,全球最大的在線健身平臺Keep正式登陸港交所,努力
  • 網紅炒股不為了賺錢,那就是耍流氓!

    來源:首席商業評論6月26日高調宣布入市,網絡名嘴大v胡錫進居然進軍了股市。在一次財經媒體峰會上,幾個財經圈媒體大佬就&ldquo;胡錫進炒股是否知道認真報道&rdquo;展開討論。有
  • 認真聊聊東方甄選:如何告別低垂的果實

    來源:山核桃作者:財經無忌爆火一年后,俞敏洪和他的東方甄選依舊是頗受外界關心的&ldquo;網紅&rdquo;。7月5日至9日,為期5天的東方甄選&ldquo;甘肅行&rdquo;首次在自有App內直播,
  • iQOO Neo8 Pro評測:旗艦雙芯加持 最強性能游戲旗艦

    【Techweb評測】去年10月,iQOO推出了一款Neo7手機,該機搭載了聯發科天璣9000+,配備獨顯芯片Pro+,帶來了同價位段最佳的游戲體驗,一經上市便受到了諸多用
Top 主站蜘蛛池模板: 黔江区| 万山特区| 阆中市| 丰台区| 科技| 呼和浩特市| 财经| 虞城县| 克什克腾旗| 清徐县| 通江县| 铁力市| 洛浦县| 郎溪县| 荆州市| 潞西市| 闸北区| 安阳市| 宁远县| 博白县| 武功县| 湄潭县| 剑阁县| 绥棱县| 太仓市| 全南县| 大庆市| 娄烦县| 西乡县| 县级市| 巧家县| 扶风县| 信丰县| 乃东县| 临武县| 屯门区| 微山县| 博罗县| 湾仔区| 林口县| 湘乡市|