2013-01-10 52 views
5

我只是學習在scala編程。 我在函數式編程方面有一些經驗,就像我在面向對象編程中一樣。 我的問題是一種簡單,但棘手:斯卡拉不可變VS可變。應該怎麼走?

Scala中應該使用哪些結構?我們是否應該堅持不變,例如。通過遍歷它來修改列表並粘貼一個新的列表,或者進行mutables?你對此有什麼看法,有什麼表現方面,內存相關方面,...

我很可能在功能風格的程序,但它往往擴大到瘋狂的努力量做的事情是很容易通過使用mutable來完成。這是情況依賴,使用什麼?

+2

這個問題很一般。我強烈建議找出你認爲需要「瘋狂」努力來解決功能性問題,並提出有關問題的問題。您可能會學到新的功能性技巧,這些技巧會使努力看起來合理 - 甚至比使用可變數據更容易! –

+9

還有其他一些問題可以解決這個問題,這個問題太模糊或者太寬泛以至於不能接受一個好的答案,但是簡而言之:做什麼最好_overall_。作爲一個經驗法則,如果沒有嚴重的缺點,請使用不可變的解決方案;在那之後,贊成一個可變狀態,其中可變狀態不會逃避本地環境(即,您正在使用的方法),然後是可變狀態至少隱藏在類中的狀態(因此不必擔心它_使用多線程時不使用 - 並記錄缺少線程安全性)。使用不變性,因爲它可以幫助你,而不是當它傷害! –

+0

關於簡單/瘋狂的比例:在處理單個線程時,可變性通常更易於編程和調試,並且在使用多線程時變得非常難以編程和調試。 –

回答

3

(我想這一定是一個重複的,但不能很容易地找到更早的類似,所以我大膽地回答...)

沒有一般的回答這個問題。斯卡拉創作者提出的經驗法則是從不變的vals和結構開始,只要它有意義就堅持。您幾乎總是可以通過這種方式爲您的問題創建可行的解決方案。但是,如果沒有,當然是務實的,並使用可變性。

一旦你有一個解決方案,你可以調整它,測試它,衡量它的表現等。如果你發現,例如,它太慢或太複雜,找出它的關鍵部分,瞭解是什麼使它成爲問題,並且 - 如果需要的話 - 使用可變變量重新實現它,理想的是保持它與程序的其餘部分隔離。不過請注意,在許多情況下,更好的解決方案可以在不可變領域內找到,所以請先試着找那裏。尤其對於像我這樣的初學者來說,它仍然經常發生,我能想出的最佳解決方案看起來很扭曲和複雜,沒有明顯的方法來改進它 - 直到在幾行代碼中看到一個簡單而優雅的解決方案,由經驗豐富的Scala開發人員創建,該開發人員控制着語言及其庫的更多功能。

+0

我也這麼認爲(必須有一個關於此的主題),並且四處看了看,但沒有發現任何東西我想我會問這個問題。 Ty爲你的答案,先生! – smoes

3

我通常遵循以下規則:

  • 切勿使用靜態可變瓦爾

  • 保留所有用戶定義的數據類型(通常情況下類)不可變的,除非它們是複製非常昂貴。這將簡化很多應用程序邏輯。

  • 如果數據結構/集合本質上是可變的(即設計爲隨時間變化而變化),那麼使用可變數據結構/集合可能是合適的。一個例子可能是當玩家移動時更新的大型遊戲世界。請記住(幾乎)永遠不會在線程之間共享這些數據結構。

  • 它的優良的方法使用可變本地變量

  • 使用功能不變的結果集。這些可以嚴格或懶惰地評估,取決於在使用的環境中什麼提供最佳性能。儘管如此,如果您使用依賴於可變集合的懶惰評估結果,請小心。

3

首選不可變爲可變狀態。只有在絕對必要時才使用可變狀態。一些值得注意的原因包括:

  • 表現。標準庫廣泛使用變量和while循環,儘管這不是慣用的Scala。然而,這不應該被仿效,除非你有配置文件來確定修改代碼更加必要會帶來顯着的性能增益。

  • I/O。 I/O或與外部世界的交互本質上是依賴於狀態的,因此必須以可變的方式處理。

這與在所有主要語言中發現的建議編碼風格沒有什麼不同,它們都是命令式的或功能性的。例如,在Java中,最好僅使用private final字段的數據對象。以不可變(和功能)方式編寫的代碼本質上更易於理解,因爲當看到val時,他們知道它永遠不會改變,從而減少任何特定對象或函數可能處於的狀態數量。

在許多但它也允許自動並行執行,例如Scala中的集合類都具有par函數,該函數將返回一個並行集合,並行集合可以自動運行諸如mapreduce之類的函數。