三.函数

       函数是可重用逻辑的核心构件。函数式编程语言特别强调支持创建高可重用、可组合的函数。
       在Scala中,函数式可重用的命名表达式。函数可以参数化,可以返回一个值。
       尽可能构建纯(pure)函数,纯函数式指:

  • 有一个或多个输入参数
  • 只使用输入参数完成计算
  • 返回一个值
  • 对于相同的输入总返回相同的值
  • 不使用或影响函数之外的任何数据
  • 不受函数之外的任何数据的影响
语法:定义无输入的函数
def  = 

语法:定义函数时指定返回类型
def :  = 

语法:完整函数定义
def (: [, ...]):  = 
例子:基本数学运算
def multiplier(x: Int, y: Int): Int = { x * y }

       最后一行将成为表达式的返回值,相应也是函数的返回值。有些情况下,可能需要在函数的表达式块结束前退出并返回一个值,可以使用return关键字来显式指定函数返回值。

例子:提前退出
scala> def safeTrim(s: String): String = {
     |   if (s == null) return null
     |   s.trim()
     | }

1.过程

       过程(procedure)是没有返回值的函数。如果有一个简单的函数,没有显式的返回类型,而且最后是一个语句,Scala编译器就会推导出这个函数的返回类型为Unit。

scala> def log(d: Double) = println(f"Got value $d%.2f")
log: (d: Double)Unit

scala> def log(d: Double): Unit = println(f"Got value $d%.2f")
log: (d: Double)Unit

2.用空括号定义函数

       要定义和调用一个无输入的函数(即没有输入参数的函数),可以使用空括号。这样可以很清楚地区分函数和值。

语法:用空括号定义函数
def ()[: ] = 
例子:
def hi(): String = "hi"

注意:有副作用(会修改其范围之外的数据)的函数,在定义时应当加空括号。

3.使用表达式块调用函数

       使用一个参数调用函数时,可以利用一个用大括号包围的表达式块发送参数,而不是用小括号包围值。通过使用表达式块调用函数,可以完成一些计算和其他动作,然后利用这个块的返回值调用函数。

语法:用表达式块调用函数
 

       有些情况下可能更适合使用表达式块来调用函数,例如必须向函数发送一个计算值时。不必先计算一个量然后把它保存在局部值中再传递给函数,完全可以在表达式块中完成计算。表达式块会在调用函数之前计算,而且表达式块的返回值将用作这个函数的参数。

例子:如何在一个表达式块中计算值来调用一个函数:
scala> def formatEuro(amt: Double) = f"$amt%.2f"
formatEuro: (amt: Double)String

scala> formatEuro(3.4645)
res9: String = 3.46

scala> formatEuro { val rate = 1.32; 0.235 + 0.7123 + rate * 5.32}
res10: String = 7.97

4.递归函数

       递归函数就是调用自身的函数,要检查某类参数或外部条件来避免函数陷入无限循环。

例子:得到一个整数的给定整数次幂
scala> def power(x: Int, n: Int): Long = {
     |   if (n >= 1) x * power(x, n-1)
     |   else 1
     | }
power: (x: Int, n: Int)Long

scala> power(2,8)
res11: Long = 256

5.嵌套函数

       可以在函数中定义另一个内部函数,这个内部函数只能在该函数中使用。

例子:取3个整数,返回其中值最大的整数
scala> def max(a: Int,b: Int,c: Int) = {
     |   def max(x: Int, y: Int) = if (x > y) x else y
     |   max(a,max(b,c))
     | }
max: (a: Int, b: Int, c: Int)Int

scala> max(42,182,19)
res12: Int = 182

       Scala函数按函数名以及其参数类型列表来区分。所以它们之间不会发生冲突。不过,即使函数名和参数类型相同,它们也不会冲突,因为局部(嵌套)函数优先于外部函数。

6.用命名参数调用函数

       调用函数的惯例是按原先定义时的顺序指定参数。但是在Scala中,可以按名调用参数,这样就可以不按顺序指定参数。

语法:按名指定参数
( = )
例子:
scala> def greet(prefix: String,name: String) = s"$prefix $name"
greet: (prefix: String, name: String)String

scala> val greeting = greet(name = "Jack", prefix = "Mr")
greeting: String = Mr Jack

7.有默认值的参数

       可以为任意参数指定默认值,使得调用者可以忽略这个参数。

语法:为函数参数指定默认值
def (:  = ): 
例子:
scala> def greet(prefix: String = "", name: String) = s"$prefix $name"
greet: (prefix: String, name: String)String

scala> val greeting = greet(name = "Paul")
greeting: String = " Paul"

       可以重新组织这个函数,让必要的参数在前,这样就可以直接调用这个函数而不再需要使用参数名:

scala> def greet(name: String, prefix: String = "") = s"$prefix $name"
greet: (name: String, prefix: String)String

scala> val greeting = greet("Ola")
greeting: String = " Ola"

       最好让必要参数在前,有默认值的参数在后。

8.Vararg参数

       Scala支持vararg参数,所以可以定义输入参数个数可变的函数。vararg参数后面不能跟非vararg,因为无法加以区分。
       要标志一个参数匹配一个或多个输入实参,在函数定义中需要该参数类型后面增加一个星号(*)

例子:vararg参数创建求和函数
scala> def sum(items: Int*): Int = {
     |   var total = 0
     |   for (i <- items) total += i
     |   total
     | }
sum: (items: Int*)Int

scala> sum(10, 20, 30)
res13: Int = 60

9.参数组

       Scala中可以把参数表分解为参数组(parameter groups),每个参数组分别用小括号分隔。

例子:
scala> def max(x:Int)(y:Int) = if (x > y) x else y
max: (x: Int)(y: Int)Int

scala> val larger = max(20)(39)
larger: Int = 39

10.类型参数

       Scala中,可以传递类型参数,类型参数指示了值参数或返回值使用的类型。

语法:定义函数的类型参数
def  [type-name](: ): ...
例子:
scala> def identity[A](a: A): A = a
identity: [A](a: A)A

scala> val s: String = identity[String]("Hello")
s: String = Hello

scala> val d: Double = identity[Double](2.717)
d: Double = 2.717

11.方法和操作符

       实际中,函数常存在于对象中,用来处理对象的数据,所以对函数更适合的说法通常是“方法”。
       方法(method)是类中定义的一个函数,这个类的所有实例都会有这个方法。

语法:用中缀点记法调用方法
.[()]
例子:加法
scala> d.+(2.721)
res14: Double = 68.363

       Scala中所有的算术运算符其实都是方法,写为简单的函数,它们使用相应的操作符符号作为函数名,并绑定到一个特定类型。

12.练习

练习(1):
scala> def compute(r: Double): Double = { 3.14 * r * r }

你可能感兴趣的:(三.函数)