基于标志更新对象的功能方法

sch*_*mmd 1 functional-programming scala

假设您正在编写一个规范化字符串的类.该类有许多配置标志.例如:

   val makeLowerCase: Boolean = true
   val removeVowels: Boolean = false
   val dropFirstCharacter: Boolean = true
Run Code Online (Sandbox Code Playgroud)

如果我正在编写可变代码,我会为该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
}
Run Code Online (Sandbox Code Playgroud)

是否有一种干净简单的方法来编写这些没有变异的东西?嵌套条件变得非常讨厌.我可以创建一个String=>Stringlambdas 列表,根据配置过滤它,然后通过它折叠字符串,但我希望有更容易的东西.

Rex*_*err 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)
Run Code Online (Sandbox Code Playgroud)

现在你把这些东西连在一起写下:

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

哪个给你:

scala> val norm = new Normer(true,false,true)
norm: Normer = Normer@2098746b

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

也就是说,可变解决方案也不错 - 只需将它保持在一个小块中就可以了.当你让可变性逃到野外时,这主要是一个问题.(其中"野性"的意思是"在你的方法之外,或在任何方法之内,而不是少数几行".)