2012-02-23 65 views
1

假設您正在編寫一個對字符串進行規範化的類。該類有許多配置標誌。例如:基於標誌更新對象的功能方法

val makeLowerCase: Boolean = true 
    val removeVowels: Boolean = false 
    val dropFirstCharacter: Boolean = true 

如果我寫可變代碼,我會寫的normalize方法如下。

def normalize(string: String) = { 
    var s = string 

    if (makeLowerCase) { 
    s = s.toLowerCase 
    } 

    if (removeVowels) { 
    s = s.replaceAll("[aeiou]", "") 
    } 

    if (dropFirstCharacter) { 
    s = s.drop(1) 
    } 

    s 
} 

有沒有一種乾淨而簡單的方式來寫這些沒有突變?嵌套條件變得非常快。我可以創建一個String=>String lambdas的列表,根據配置對其進行過濾,然後通過它摺疊字符串,但我希望有一些更容易的方法。

+2

一個小功能中避免突變比可讀性重要得多。只要你的功能沒有產生外部副作用,你不應該擔心它。例如,不可能在沒有突變的情況下高效地進行排序,但只要您改變副本,功能外的任何人都無法區分。 – 2012-02-23 03:26:56

回答

4

如果使用scalaz|>運營商或在您的公用事業類中定義一個類似的,你可以這樣做:

case class N(
    makeLowerCase: Boolean = true, 
    removeVowels: Boolean = false, 
    dropFirstCharacter: Boolean = true) { 

    def normalize(string: String) = (
    string 
     |> (s => if (makeLowerCase) s.toLowerCase else s) 
     |> (s => if (removeVowels) s.replaceAll("[aeiou]", "") else s) 
     |> (s => if (dropFirstCharacter) s.drop(1) else s) 
) 

} 

N(removeVowels=true).normalize("DDABCUI") 
// res1: String = dbc 
6

最好的辦法是定義自己的方法:

class ConditionalMapper[A](a: A) { 
    def changeCheck(p: A => Boolean)(f: A => A) = if (p(a)) f(a) else a 
    def changeIf(b: Boolean)(f: A => A) = if (b) f(a) else a 
} 
implicit def conditionally_change_anything[A](a: A) = new ConditionalMapper(a) 

現在你把這些東西鏈接在一起並寫下:

class Normer(makeLC: Boolean, remVowel: Boolean, dropFirst: Boolean) { 
    def normalize(s: String) = { 
    s.changeIf(makeLC) { _.toLowerCase } 
    .changeIf(remVowel) { _.replaceAll("[aeiou]","") } 
    .changeIf(dropFirst){ _.substring(1) } 
    } 
} 

Whic小時之後獲得您:

scala> val norm = new Normer(true,false,true) 
norm: Normer = [email protected] 

scala> norm.normalize("The Quick Brown Fox Jumps Over The Lazy Dog") 
res1: String = he quick brown fox jumps over the lazy dog 

儘管如此,可變的解決方案是不壞的 - 只要它保持一個小街區,你會被罰款。當你讓可變性逃到野外時,這主要是一個問題。 (其中「野生」的意思是「你的方法外,或內比長線的屈指可數的任何方法」。)