[英]In Scala, how would I combine event driven programming with a functional approach?
[英]How to rewrite this code in Scala using a Functional Programming approach
下面是執行一些URL規范化的代碼片段。 如何重寫它只使用不可變變量?
當然,不要讓它更大或更復雜。
private def normalizeUrl(url0: String) = {
var url = url0
if (url.endsWith("/")) {
url = url.dropRight(1)
}
if (url.indexOf(':') < 0 ||
url.indexOf(':') == 1) { //windows absolute path
url = "file:" + url;
}
url = url.replaceAll("\\\\", "/");
url
}
如果你想將一堆if / then條件鏈接起來修改一個字符串,你可以考慮添加一個隱式類來處理if / then評估,如下所示:
object UrlPimping{
implicit class PimpedUrl(val url:String) extends AnyVal{
def changeIf(condition:String => Boolean)(f:String => String):String = {
if (condition(url)) f(url)
else url
}
}
}
private def normalizeUrl(url: String) = {
import UrlPimping._
url.
changeIf(_.endsWith("/"))(_.dropRight(1)).
changeIf(u => u.indexOf(':') < 0 || u.indexOf(':') == 1)(u => s"file:$u").
replaceAll("\\\\", "/")
}
如果你只考慮這兩個條件,這將是一種過度殺傷,但如果你有更多的條件可能會很好,這是一個常見的模式。
考慮函數式編程的名稱 ! 重點是用函數替換變量。
private def normalizeProtocol(url: String) =
if (url.endsWith("/")) url.dropRight(1) else url
private def removeEndingSlash(url: String) =
if (url.indexOf(':') < 0 ||
url.indexOf(':') == 1) //windows absolute path
"file:" + url
else
url
private def replaceSlash(url: String) =
url.replaceAll("\\\\", "/");
private def normalizeUrl(url: String) =
replaceSlash(normalizeProtocol(removeEndingSlash(url)))
CM Baxter指出,最后一個函數也可以寫成
private val normalizeUrl =
removeEndingSlash _ andThen
normalizeProtocol andThen
replaceSlash
我留給你決定哪個更清晰。
例如,考慮一種具有中間結果的直觀方法,以及if-else
表達式,
private def normalizeUrl(url0: String) = {
val url1 =
if (url0.endsWith("/")) url0.dropRight(1)
else url0
val url2 =
if (url1.indexOf(':') < 0 || url1.indexOf(':') == 1) "file:" + url1
else url1
url2.replaceAll("\\\\", "/")
}
請注意返回最后一個帶有replaceAll
表達式url2
。
一些重構和鏈接怎么樣? 這里不需要你的var url
。
我認為這會奏效:
private def normalizeUrl(url: String) = {
(if (url.indexOf(':') < 0 || url.indexOf(':') == 1) {
"file:"
} else {
""
}) + (if (url.endsWith("/")) {
url.dropRight(1)
} else {
url
}).replaceAll("\\\\", "/")
}
當然,為了更好的可讀性,我建議使用這樣的東西:
private def normalizeUrl(url: String) = {
val prefix = if (url.indexOf(':') < 0 || url.indexOf(':') == 1) "file:" else ""
val noSlash = if (url.endsWith("/")) url.dropRight(1) else url
(prefix + noSlash).replaceAll("\\\\", "/")
}
不要害怕使用多個val。 :)
一種選擇是使用Reader Monad並在其上映射函數:
val normalizeUrl: Reader[String, String] = Reader[String, String](s => s)
.map(url => if (url.endsWith("/")) { url.dropRight(1) } else url)
.map(url => if (url.indexOf(':') < 0 || url.indexOf(':') == 1) "file:" + url else url)
.map(url => url.replaceAll("\\\\", "/"))
然后就像任何函數一樣調用它:
normalizeUrl("some\\\\url")
我想我更喜歡榆樹的解決方案
這是另一個。 你寫的測試為你的函數(REACH removeEndSlash
, removeSlashes
和removeSlashes
def normalizeURL(url: String) = {
def removeEndSlash(u: String): String = if (u.endsWith("/")) u.dropRight(1) else u
def isFile(u: String): String = {
val idx = u.indexOf(':')
if (idx < 0 || idx == 1)
"file:" + u
else
u
}
def removeSlashes( u : String ) = u.replaceAll("\\\\", "/")
removeSlashes(isFile(removeEndSlash(url)))
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.