参数列表 => 方法体/返回值 比如:
(x: Int) => x+1
比如在 filter 中可以这样写,会自动推断 x 的类型
x => x+1
或者
_ + 1
或者
(x: Int) => x+1
或者
{x:Int => x+1}
或者单独声明一个变量
val g: Int => Int = _+1
省略 _ , 当只有一个实参,并且函数只有一个形参,那么编译器会直接传递这个参数到这个函数的形参列表。因此可以省略 _ 。除此之外,不能省略 _ 。比如
ds.foreach(println)
多个_的使用
val f = (_ :Int ) + ( _ :Int)
f (5,10) //output: 15
每个 _ 都是一个参数,前面的 _ 代表参数1,后面的 _ 代表参数2
函数是 trait Function1 - Function12 特质的集合。具有一个参数的函数是Function1特质的一个实例。这个特质定义了apply()语法糖,让你调用一个对象时就像你在调用一个函数。你可以使用 object 或 class 实现。
object addOne extends Function1[Int, Int] {
def apply(m: Int): Int = m + 1
}
class AddOne extends Function1[Int, Int] {
def apply(m: Int): Int = m + 1
}
也可用字面量形式声明特质 Int => Int
class AddOne extends (Int => Int) {
def apply(m: Int): Int = m + 1
}
比如
def sum = (_:Int) + (_ :Int) + (_ :Int)
val b = sum ( 1 , _, 3) //偏应用函数
b(2) // output: 6
略
可变参数(相当于其它编程语言中的 rest, spread 扩展符)
def main(args: Array[String]): Unit = {
echo(2,3)
//仅可在传递参数时使用 : _* 这个注解
echo(1 to 3:_*)
}
def echo(args:Int*): Unit = {
for (elem <- args) {println(elem)}
}
具名参数传递
通常需要按照顺序去传参数
def main(args: Array[String]): Unit = {
hi("lisi", age = 2, "li")
hi(city = "lisi", name = "li", age = 3)
}
def hi(name: String, age: Int, city: String) {
println(name, age)
}
默认参数
def hi(name:String, age:Int=20): Unit = {
println(name, age)
}
使用 def 声明的即为方法,使用 val 与 => 表达的即为函数
class test {
def m1(x:Int) = x+3
val f1 = (x:Int) => x+3
val f2 = m1 _
val f3 : (Int) => Int = m1
def m2(x:Int)(y:Int) = x + y
def m3 = m2(20)
val f4 = m3 _
}
注意
函数才有 compose, andThen, curried 这些操作。方法如果要使用这些操作,必须先转换成函数。
转换
- 加下划线(如 f2),或者声明变量(如 f3)
- ETA 展开。一个方法接受一个函数作为参数,通常可以直接传递方法名而不必加下划线。此方法不能有重载方法。比如 Function.uncurried 有多个重载方法,因此传参时必须显式转换为函数
无参方法使用点表达式
如果有一个参数,并且没有副作用,可以使用 infix,否则的话建议使用点表达式
高阶函数,因为需要链式调用,可使用 infix
// recommended
names.toList
// discourage
names toList
// recommended
names.mkString(",")
// also sometimes seen; controversial
names mkString ","
// wrong - has side-effects
javaList add item
// wrong!
names.map { _.toUpperCase }.filter { _.length > 5 }
// right!
names map { _.toUpperCase } filter { _.length > 5 }
特性
- 不处理所有可能的输入,只处理那些能与至少一个 case 语句匹配的输入
- 可以用 isDefineAt 方法测试特定输入是否与偏函数匹配
- 偏函数之间可以链式连接,如 OrElse、 andThen、applyOrElse
val pf1:PartialFunction[Any, String] = {case s:String => "YES"}
val pf2:PartialFunction[Any, String] = {case d:Double => "YES"}
val pf = pf1 orElse pf2
pf.isDefinedAt("d") // Boolean
try { pf("d").toString } catch { case _:MatchError => "ERROR!" }
与偏应用函数的区别
- 偏作用函数是一个函数,带部分参数而非全部参数列表的函数。
- 偏函数可以看作是一个特殊的单参数的函数。 一个使用 case 字面量表示的偏函数,本质是 trait PartialFunction[A,B] 的一个实现(该 Trait 接收一个类型为A的参数,返回一个类型为B的结果,并未对该类型的所有值都有定义)。
与 Option转换
val sum2: PartialFunction[List[Int], Int] = {
case x :: y :: _ => x + y
}
sum2.lift(List(2,3)) // Some(5)
使用 case 语句替代函数写法
scala> case class PhoneExt(name: String, ext: Int)
defined class PhoneExt
scala> val extensions = List(PhoneExt("steve", 100), PhoneExt("robey", 200))
extensions: List[PhoneExt] = List(PhoneExt(steve,100), PhoneExt(robey,200))
scala> extensions.filter { case PhoneExt(name, extension) => extension < 200 }
res0: List[PhoneExt] = List(PhoneExt(steve,100))
解释:PartialFunction 是 Function的子类型,所以filter也可以使用 PartialFunction!
相关问题 什么是 case 语句? 这是一个名为PartialFunction的函数的子类。
多个case语句的集合是什么? 他们是共同组合在一起的多个PartialFunction。