将类似函数传递给Scala map()时DRY

时间:2013-11-24 15:35:04

标签: scala dry

def doubleList(noList:List[Int]) = {
    val result = noList.map{ number =>
        number*2
    }
    result
}

def halfList(noList:List[Int]) = {
    val result = noList.map{ number =>
        number/2
    }
    result
}

def mapFunctionDRY(noList:List[Int])(codeBlock: () => Int) = {

}

println(halfList(List(1,2,3)))
println(doubleList(List(1,2,4)))

我正在玩scala并注意到上述两个函数doubleListhalfList中的DRY(不要重复自己)。我希望函数中的公共代码被隔离,只需传递不同的代码块。这样我的代码就不会违反DRY原则。我知道你可以在scala中传入代码块作为参数。这就是我打算在mapFunctionDRY

中做的事情

我希望mapFunctionDRY以这种方式

def mapFunctionDRY(noList:List[Int])(codeBlock: () => Int) = {
    noList.map{ number =>
        codeBlock()
    }
}

doubleListhalfList中的代码与此类似

def doubleList(noList:List[Int]) = { mapFunctionDRY(noList){ () => number*2 } }

但如果我这样做,我会得到编译错误。在这种情况下,如何将代码作为参数传入,以避免违反DRY。可以进一步减少此代码以使其干燥吗?

5 个答案:

答案 0 :(得分:5)

你不需要重新发明地图确实很干的工作:

def double(x: Int) = x * 2
def half(x: Int) = x / 2
val xs = List(1,2,3,4)
xs.map(double)
// List[Int] = List(2, 4, 6, 8)

xs.map(half)
// List[Int] = List(0, 1, 1, 2)

答案 1 :(得分:2)

发生编译错误是因为您希望将每个Int映射到另一个Int。 codeBlock: () => Int是一个不带参数的函数。

codeBlock: Int => Int应该做你想做的事。然后你可以定义这样的东西:

def doubleList(noList:List[Int]) = { mapFunctionDRY(noList){ (number : Int) => number*2 } }

虽然没有测试过。

编辑:和其他人一样说。这个函数不是很有用,因为它就像map一样,但在某种意义上它只能应用于List [Int]

答案 2 :(得分:2)

为什么要围绕map构建一个包装器,它实际上为您的问题提供了最干净的解决方案?我建议采用不同的策略:

val mapDouble = (x: Int) => x * 2
val mapHalf = (x: Int) => x / 2
List(1, 2, 3).map(mapDouble)
List(1, 2, 3).map(mapHalf)

答案 3 :(得分:1)

您的功能在列表的一个元素上运行。因此,我会将其更改为codeBlock,而不是() => Int(Int) => Int。所以给定一个列表的一个元素你想用它做什么。

这导致以下代码:

def mapFunctionDRY(noList:List[Int])(elementFn: (Int) => Int) = {
  noList.map{ number =>
    elementFn(number)
  }
}

如果你是短代码,那么等效代码是:

def mapFunctionDRY(noList:List[Int])(elementFn: (Int) => Int) = noList.map(elementFn)

还有很多其他方法可以保持干爽。例如,您可以单独定义操作以便能够重复使用它们:

val doubleOperation: Int => Int = _ * 2
val halfOperation: Int => Int = _ / 2
def doubleList(noList:List[Int]) = noList.map(doubleOperation)
def halfList(noList:List[Int]) = noList.map(halfOperation)

或者您可以使用函数currying来保存自己的一行代码:

def mapFunction(fn: (Int) => Int)(noList: List[Int]) = noList.map(fn)
val doubleList = mapFunction(_ * 2)
val halfList = mapFunction(_ / 2)

答案 4 :(得分:1)

我认为你在寻找的就是这方面的结论。

 def func(factor:Double)(noList:List[Int]) ={
     val result = noList.map{ number =>
            number*factor
        }
        result

现在你可以用func(0.5f)(noList)或func(1.0f)(noList)传递这个函数

您甚至可以参考功能的不同版本。

halfed = x:List[Int] => func(0.5f)(x)
doubled = x:List[Int] => func(2.0f)(x)