2.1 zio入门——把函数作用作为工作蓝图
ZIO標準庫的核心數據類型是ZIO[R, E, A],這種類型的值被稱為函數式作用
函數式作用是并發工作流的一種藍圖,如圖1所示。該藍圖本質上是純描述性的,必須執行才能觀察到任何副作用,例如與數據庫的交互,日志記錄,流傳輸 網絡中的數據,或接受請求。
ZIO [R,E,A]類型的函數式作用要求您在運行的時候提供R類型的值,并且在執行效果時,它可能會執行失敗返回類型為E(錯誤類型),或者執行成功返回類型為A(成功類型)。
稍后我們將詳細討論這些類型參數。但是首先,我們需要了解將效果變為藍圖意味著什么。
在傳統的過程編程中,我們習慣于代碼的每一行直接與外界交互。例如,考慮以下代碼片段:
scala程序一旦運行goShopping變量,就會立刻輸出 Going to the grocery store. 這種風格的編程方式是過程式編程。基本上所有程序員都熟悉這種編程方式,因為大多數編程語言天生就是過程式的。
對于簡單的程序而言,過程式編程是非常方便的。但是當我們這樣寫程序的時候,我們想要做的事情(去商店)與我們想要做的事情(現在去商店)糾纏不清。這種糾纏可能導致許多難以理解和測試的樣板代碼,難以更改,并且充滿了直到生產才發現的細微錯誤。
例如,假設我們實際上不想現在去雜貨店,而是從現在開始一個小時。我們可能會這樣去編寫代碼:
在這段程序中我們創建了一個executor,在一小時后執行我們的 goShopping 操作。然后在程序執行完之后 shut down 調度器。
該解決方案不僅涉及難以理解,測試和難以更改的樣板代碼,而且還存在一個細微的錯誤!
因為goShopping是直接執行的,而不是工作計劃,所以一旦JVM加載 goShopping,就會將 “Going to the grocery store”打印到控制臺。因此,我們現在要去雜貨店,而不是現在的一個小時!
實際上,我們計劃在一小時內執行的唯一操作就是返回goShopping的Unit值,這根本不需要執行任何操作。
在這種情況下,我們可以通過將goShopping定義為def而不是val來推遲其計算,從而解決問題。但是這種方法脆弱且容易出錯,迫使我們仔細考慮何時對程序中的每個語句進行求值,而不再是語句的順序。
我們還必須注意不要過早計算。我們可能將其賦值或放入數據結構中,這可能會導致過早計算。好像我們談購物一樣,但是一旦提到“食品”一詞,它們就已經在門口了!實際上我們只是打算去購買而已。
解決此問題(以及并發編程中的大多數問題)的方法是在程序值中創建描述我們想要做什么的語句。這樣,我們就可以將我們想做的事情與想怎么去做這件事情分開。
下面這段代碼展示了怎么用zio編寫這段程序:
import zio._ val goShopping = ZIO.effect(println("Going to the grocery store"))在這段程序中我們用 effect 的構造函數創建了一個 goShopping 的函數式作用。這個 effect 只是描述了我們要去超時,但是事實上沒有立刻做任何事。這主要是因為 effect 的參數是 effect :=> A, 這是 () => A 的簡寫。可以在 scala REPL中測試這段代碼,你并不會得到任何輸出。
為了去超市,我們必須運行這個執行和定義分開的作用。從而使我們可以消除上面提到的問題,并極大地簡化代碼。
通過這種定義 go shopping的方式,我們現在可以闡述 在怎么把 ”how“ 和 “what” 分開,然后通過組合作用的方式解決復雜業務問題。
下面的示例通過 ZIO類型的靜態方法 delay ,將 goShopping函數轉換為一個一小時后執行的副作用。
import zio.clock._ import zio.duration._ val goShoppingLater = goShopping.delay(1.hour)得益于可以將工作流描述為普通的不可變值功能,我們不必擔心怎么去定義goShopping又或者過早的運行他。同樣,delay 運算符返回的值只是另一個effect,因此我們可以輕松地使用它以相同的方式構建更復雜的程序。
在ZIO中,每個ZIO效果都只是一種描述-并發工作流程的藍圖。在編寫程序時,我們創建了更大,更復雜的藍圖,這些藍圖更接近于解決業務問題。當我們完成并具有描述我們需要做的所有事情的效果時,我們將其交給ZIO runtime,ZIO runtime將執行該藍圖并產生程序結果。
那么我們如何實際運行ZIO效果?最簡單的方法是擴展App特性并實現run方法,如以下代碼片段所示:
import zio._ object GroceryStore extends App { def run(args: List[String]) = goShopping.exitCode }run函數要求我們返回一個ExitCode,該退出代碼描述了進程終止時要使用的退出值。 在上定義的exitCode方法是一種方便的方法,可將所有成功都轉換為ExitCode(0),將所有失敗轉換為ExitCode(1)。
總結
以上是生活随笔為你收集整理的2.1 zio入门——把函数作用作为工作蓝图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: day3-转自金角大王
- 下一篇: 动态加载省市区