Skip to content

Latest commit

 

History

History
247 lines (171 loc) · 5.39 KB

05.函数.md

File metadata and controls

247 lines (171 loc) · 5.39 KB

05 函数

1 函数字面量

参数列表 => 方法体/返回值 比如:

(x: Int) => x+1

2 函数字面量的简化写法

比如在 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

3 函数即对象

函数是 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
}

3 偏应用函数

比如

def sum = (_:Int) + (_ :Int) + (_ :Int)

val b = sum ( 1 , _, 3) //偏应用函数
b(2) // output: 6

4 闭包

5 可变参数、命名参数与缺省参数

可变参数(相当于其它编程语言中的 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)
}

6 函数与方法的区别

参考

使用 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 有多个重载方法,因此传参时必须显式转换为函数

7 infix 表达式

参考

无参方法使用点表达式
如果有一个参数,并且没有副作用,可以使用 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 }

8 偏函数

特性

  1. 不处理所有可能的输入,只处理那些能与至少一个 case 语句匹配的输入
  2. 可以用 isDefineAt 方法测试特定输入是否与偏函数匹配
  3. 偏函数之间可以链式连接,如 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。