【问题标题】:DRY when passing similar functions to Scala map()将类似函数传递给 Scala map() 时干燥
【发布时间】:2013-11-24 15:35:03
【问题描述】:
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。可以进一步减少此代码以使其保持干燥吗?

【问题讨论】:

    标签: scala dry


    【解决方案1】:

    你不需要重新发明地图所做的工作:

    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)
    

    【讨论】:

    • 即List(1,2,3,4) map(_*2) 和 List(1,2,3,4) map(_/2)
    【解决方案2】:

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

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

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

    还没有测试过。

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

    【讨论】:

      【解决方案3】:

      为什么要围绕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)
      

      【讨论】:

        【解决方案4】:

        您的函数对列表的一个元素进行操作。因此,我将把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)
        

        或者你可以使用函数柯里化来节省一行代码:

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

        【讨论】:

          【解决方案5】:

          我认为您在这方面正在寻找的是 Currying。

           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)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-06-19
            • 1970-01-01
            • 2015-07-18
            • 2015-09-11
            • 1970-01-01
            • 2021-10-23
            • 2011-12-01
            相关资源
            最近更新 更多