scala学习手记29 - 偏应用函数

调用函数可以说成是将函数应用于实参。如果传入所有的预期的参数,就完全应用了这个函数。如果只传入几个参数,就会得到一个偏应用函数。

偏应用函数是一个特殊的概念,在scala中它是使用val定义的,但是在使用时它却更像是一个函数。偏应用函数的定义更接近于python中有默认值的函数(scala实在是和python有太多相似的地方了)。

先来看一个例子:

import java.util.Date

def log(date: Date, message: String) {
  //...
  println(date + "----" + message)
}
val date = new Date
log(date, "message1")
log(date, "message2")
log(date, "message3")

示例中定义了一个log函数,在log函数中需要传入两个参数date和message。在之后又多次调用log函数,调用时使用了相同的date和不同的message。很显然,这里多次使用相同的date会让人有些小小的不耐烦。所以scala就提供了一个方案让人打消掉这小小的不耐烦:将log函数偏应用到date上,可以避免每次使用都要调用它。

看一下是如何实现的:

val logWithDateBound = log(new Date, _: String)
logWithDateBound("message1")
logWithDateBound("message2")
logWithDateBound("message3")

在示例代码中先将一个值绑定到date参数上,然后用“_”使第二个参数未绑定,这样就构成了一个偏应用函数。然后这个偏应用函数被存到logWithDateBound这个引用里。随后就可以使用不同的message来调用这个新的函数了。

说到底这里还是定义了一个新的函数,不过在定义和使用上都比较自由罢了。说实话,目前我是觉得这个特性是有些华而不实的。这个特性的引入更像是在炒作一个旧有的概念,新瓶装旧酒总让人提不起兴致来。

看下教材上的解释:当创建偏应用函数时,Scala内部会创建一个新类,它有一个特殊的apply()方法。调用偏应用函数,实际上是调用这个apply方法。

##########

时间: 2024-10-04 00:04:50

scala学习手记29 - 偏应用函数的相关文章

scala学习手记23 - 函数值

scala的一个最主要的特性就是支持函数编程.函数是函数编程中的一等公民:函数可以作为参数传递给其他函数,可以作为其他函数的返回值,甚至可以在其它函数中嵌套.这些高阶函数称为函数值. 举一个简单的例子:从1到某个数求和.使用Java很容易实现: int sum(int max){ int result = 0; for (int i = 0; i <= max; i++) { result +=i; } return result; } 使用scala实现也没有多大区别. 现在再扩展下需求:对某

scala学习手记40 - 使用case类

前面两节我们已经多次接触过case关键字了.case关键字不仅可以用在match/case中来执行模式匹配,也可以用来修饰类.不过用case修饰的类也主要是用来做模式匹配.在上一节曾经提到过match可以是Any类型的所有类,为什么还需要使用case关键字来修饰呢?假定有这样一个场景:我们要接收和处理股票交易信息,买卖消息通常会带有一些信息,诸如股票名称.数量.把这些信息存到对象里会很方便,但是如何对他们进行模式匹配呢?这时我们就会用到case类了.case类是模式匹配器(pattern mat

scala学习手记17 - 容器和类型推断

关于scala的类型推断前面已经提到过多次.再来看一下下面这个例子: import java.util._ var list1: List[Int] = new ArrayList[Int] var list2 = new ArrayList[Int] list2 add 1 list2 add 2 var total = 0 for (index <- 0 until list2.size()) { total += list2.get(index) } println("Total i

scala学习手记14 - 单例对象

java中的单例模式都很熟悉了:简单地说就是一个类只能有一个实例.在scala中创建单例对象非常简单,创建类时使用object关键字替换class即可.因为单例类无法初始化,所以不能向它的主构造函数传递参数. 下面是一个单例的示例: class Marker(val color: String) { println("Creating " + this) override def toString(): String = "marker color " + colo

scala学习手记8 - 自适应的默认做法

scala有一些默认做法,会让代码更简洁.更易读写,下面列出了这样几个特性: 1. 支持脚本.scala支持脚本,因此无须将所有的代码都放到类里.如果脚本可以满足需求,就将代码放到一个脚本里,无须再创建一个冗余的类. 2. return是可选的.如果没有写return关键字,方法调用会自动返回最后一个求值的表达式--如果它符合方法声明的返回值类型. 3. 分号":"是可选的.不必在每个语句的后面都写上分号,这样会使代码更简洁.如果语句太长或者包含多行的话可以换行继续写,scala能够识

scala学习手记2 - scala中的循环

先来看一段Java中的循环: for (int i = 1; i < 4; i++) { System.out.print(i + ","); } 毫无疑问,scala可以让这个循环更加简洁.根据上一节中的内容,没有必要显示指定变量i的类型,我们甚至不需要声明这个变量.其次输出的语句也可以更加简洁一些,在scala中可以直接使用println()这个方法输出字符串.最后scala的循环结构也是非常的轻量级.好了,可以看一下代码了: for (i <- 1 to 3) { p

scala学习手记 - case表达式里的模式变量和常量

再来看一下之前的一段代码: def process(input: Any) { input match { case (a: Int, b: Int) => println("Processing (int, int)... ") case (a: Double, b: Double) => println("Processing (double, double)... ") case msg: Int if (msg > 1000000) =&g

scala学习手记38 - 方法命名约定和for表达式

方法命名约定 之前在学习<运算符重载>一节时曾经说过一个方法命名约定:方法的第一个字符决定了方法的优先级.现在再说另一个命名约定:如果方法以冒号(:)结尾,则调用目标是运算符后面的实例. 比如下面这个例子: class Cow { def ^(moon: Moon) = println("Cow jumped over the moon") } class Moon { def ^:(cow: Cow) = println("This cow jumped ove

scala学习手记9 - =和==

= 赋值运算 scala的赋值运算和java的有着很大的不同.如a=b这样的赋值运算,在Java中返回值是a的值,在scala中返回的则是Unit.Unit是值类型,全局只存在唯一的值,即(),通常Unit只用来声明函数或方法的返回值,其他场景基本是没有意义的.这样就很容易导致一些错误地使用,比如a=b=c这样的赋值运算在java中是绝对可以的,但是在scala中运行就会报错.看一段代码: var a, b, c = 1 a = b=c println(a) 上面这段代码还没有执行就在IDE中报