高阶函数
什么是高阶函数?
在scala中,函数可以作为参数来传递。下面的代码定义一个接受函数作为参数的函数:
// 函数定义 def operation(func:(Int, Int) => Int) = { val result = func(4,4) println(result) } // 接下来,定义一个与预期签名匹配的函数: val add = (x: Int, y:Int) => { x + y } // 将add函数作为参数传递给operation函数 operation(add) // 以上可以简写,相当于 val func = (x: Int, y:Int) => { x + y } operation((x: Int, y:Int) => { x + y })
能接收函数参数的函数,或者返回值为函数的函数,称为"高阶函数",比如这里的operation就是一个高阶函数。
下面定义一个返回一个函数的高阶函数:
def greeting() = { println("any any ...") (name: String) => {"hello" + " " + name} // 最后一行,是函数的返回值 } // 调用函数greeting,得到它的返回值,这个返回值本身又是一个函数: // 相当于 val func = (name: String) => {"hello" + " " + name} val func = greeting() // 调用func func("朋友")
在这里,greeting函数就是一个“高阶函数”,因为它返回了一个函数。所以可以这样调用:
greeting()("朋友")
下面是另一个使用高阶函数的示例:
def functionOps3: Unit = { // 1.匿名函数作为参数 def highOrderFunc(name:String, func:(String) => Unit): Unit = { func(name) } highOrderFunc("xpleaf", (name:String) => println("Hello, " + name)) // 2.将匿名函数作为返回值传递给另外一个函数 def getGoodBayFunction(gMsg: String) = (gName: String) => println(gMsg + ", " + gName) val goodbayFunction = getGoodBayFunction("good bye") goodbayFunction("xpleaf") } functionOps3
call-by-name与call-by-value
本节是前一节高阶函数内容的延续,我们将展示按call-by-name和call-by-value函数参数之间的区别。
在下面的例子中,我们首先定义一个包含Tuple3元素的List,代表一组订单。我们定义一个函数循环遍历列表中的每个Tuple3元素来计算总成本。
假设商品在世界各地销售,因此需要将购买订单的总成本转换为使用的当地货币。我们分别定义了call-by-value函数参数调用和call-by-name函数参数的调用。请注意其中的区别。
import scala.util.Random object demo { // 定义一个placeOrder()函数,它将获取订单列表。 // 但是该函数还有一个exchangeRate参数,用于将总成本转换为当地货币。 // call-by-value // 这意味着任何传递的汇率exchangeRate只会被计算一次 def placeOrder(orders: List[(String, Int, Double)])(exchangeRate: Double): Double = { var totalCost: Double = 0.0 orders.foreach {order => val costOfItem = order._2 * order._3 * exchangeRate println(s"Cost of ${order._2} ${order._1} = £$costOfItem") totalCost += costOfItem } totalCost } // call-by-name // 调用名称函数参数exchangeRate: => Double将在每次调用任何exchangeRate函数时计算它 def placeOrderWithByNameParameter(orders:List[(String, Int, Double)])(exchangeRate:=> Double):Double = { var totalCost: Double = 0.0 orders.foreach {order => val costOfItem = order._2 * order._3 * exchangeRate println(s"Cost of ${order._2} ${order._1} = £$costOfItem") totalCost += costOfItem } totalCost } def main(args: Array[String]): Unit = { val listOrders = List(("苹果", 5, 2.50), ("香蕉", 10, 3.50)) println(s"订单总费用 = £${placeOrder(listOrders)(0.5)}") println(s"订单总费用 = £${placeOrderWithByNameParameter(listOrders)(0.5)}") // 创建一个函数,它将随机生成美元USD到英镑GBP的货币转换 val randomExchangeRate = new Random(10) def usdToGbp: Double = { val rate = randomExchangeRate.nextDouble() println(s"取美元对英镑的汇率 = $rate") rate } // 调用call-by-name参数的函数 println(s"订单总费用 = £${placeOrderWithByNameParameter(listOrders)(usdToGbp)}") // 对于列表中的每个订单,都将创建一个新的汇率,这是因为每次都在计算call-by-name函数usdToGbp函数 } }
执行以上代码,输出结果如下:
Cost of 5 苹果 = £6.25 Cost of 10 香蕉 = £17.5 订单总费用 = £23.75 Cost of 5 苹果 = £6.25 Cost of 10 香蕉 = £17.5 订单总费用 = £23.75 取美元对英镑的汇率 = 0.7304302967434272 Cost of 5 苹果 = £9.13037870929284 取美元对英镑的汇率 = 0.2578027905957804 Cost of 10 香蕉 = £9.023097670852312 订单总费用 = £18.15347638014515