02-scala 函数&方法进阶

63 阅读2分钟

作用域省略

scala中,如果方法只有一个参数,可以省略.作用域符号,给出一个说明:

package example

class Person(var age: Int) {
  def setAge(n: Int) = age = n
}

object MyExample {
  def main(args: Array[String]): Unit = {
    val p = new Person(0)
    p setAge 10  // 这里省略.和()
    println(p.age)
  }
}

高阶函数

scala中,函数是“一等公民”,即函数可以类似变量那样,可以赋值、作为其他函数or方法的输入、作为返回值。当一个函数作为上述的作用时,我们称之为高阶函数。举个例子:

package example

object MyExample {
  
  def main(args: Array[String]): Unit = {
    val salaries = Seq(1000, 2000, 3000)
    val times2 = (x: Int) => x * 2  // 作为变量赋值
    val newSalaries = salaries.map(times2)  // 作为函数参数
    println(newSalaries.toString())
    val newSalaries1 = newSalaries.map(x => x * 2)  // 使用匿名函数
    println(newSalaries1.toString())
    val newSalaries2 = newSalaries1.map(_ * 2)  // 简写
    println(newSalaries2.toString())
  }
}

代码输出:

List(2000, 4000, 6000)
List(4000, 8000, 12000)
List(8000, 16000, 24000)

我们也可以强制转换方法为函数,举个例子:

package example

case class TemperatureConverter(temperatures: Seq[Double]) {

  def convertCtoF(temp: Double): Double = temp * 2 + 38
  // 这里map的函数直接使用方法,并转换成函数
  def convertTempList: Seq[Double] = temperatures.map(convertCtoF)
}

object MyExample {
  
  def main(args: Array[String]): Unit = {
    val tc = TemperatureConverter(Seq(20.0, 18.7, 13.2, 14.3))
    val temps = tc.convertTempList
    println(temps.toString)
  }
}

代码输出:

List(78.0, 75.4, 64.4, 66.6)

我们也可以在一个类中,把其他类的方法z我们也可以在一个类中,把其他类的方法转换成函数,举个例子:

package example

class Foo {
  def add2(n: Int): Int = n + 2
}

object Foo {
  def add3(n: Int): Int = n + 3
}

object MyExample {
  
  def main(args: Array[String]): Unit = {
    val s = Seq(1, 2, 3, 4)
    val foo = new Foo
    val s1 = s.map(foo.add2)  // 需要使用实例化后的对象
    println(s1.toString)
    val s2 = s.map(Foo.add3)  // object中的方法可以直接引用
    println(s2.toString)
  }
}

代码输出:

List(3, 4, 5, 6)
List(4, 5, 6, 7)

函数也可以作为其他函数或者方法的参数,举个例子:

package example

class Num2(a: Int, b: Int) {
  // op是一个方法
  def numOp(op: (Int, Int) => Int): Int = {
    val x = a + 10
    val y = b * 2
    op(a, b)
  }
}
object MyExample {
  
  def main(args: Array[String]): Unit = {
    val num2 = new Num2(10, 2)
    val op = (a: Int, b: Int) => a + b  // 定义方法
    val res = num2.numOp(op)
    println(res)
  }
}

函数也可以作为返回值,举个例子:

package example

object  MathFactory {
  def numOp(n: Int): (Int) => Int =  {
    if (n > 0) {
      (a: Int) => a * 2
    } else {
      (b: Int) => b * 3
    }
  }
}

object MyExample {
  
  def main(args: Array[String]): Unit = {
    val n = 3
    val op1 = MathFactory.numOp(1)
    val res1 = op1(n)
    println(res1)
    val op2 = MathFactory.numOp(-1)
    val res2 = op2(n)
    println(res2)
  }
}

代码输出:

6
9

函数内部也可以有嵌套方法,比如:

package example

object MyExample {
  
  def main(args: Array[String]): Unit = {
    def add2(n: Int): Int = n + 2  // main方法内部继续嵌套main方法
    println(add2(3))
  }
}

函数柯理化

直接上代码:

package example

object MyExample {

  def normalize(base: Int)(a: Int, b: Int, c: Int): Int = {
    println(s"base=$base")
    (a + b + c) / base
  }
  
  def main(args: Array[String]): Unit = {
    // 函数柯理化,注意这里的下划线表示省略参数
    def carry2 = normalize(2)_
    val res = carry2(1, 2, 3)
    println(res)
  }
}

代码输出:

base=2
3