scala开发快速入门 | 第五篇 方法和函数

本文详细介绍了Scala语言中的函数定义规则、常见格式及特性,包括方法定义、柯里化、可变参数、默认值与命名参数、闭包、部分应用函数等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Scala函数的定义规则

1)定义方法的基本格式是:def 方法名称(参数列表):返回值类型 = {方法体}

def function1(param1: String, param2: String): String = {
  "[" + param1 + "]" + ",[" + param2 + "]"

}

Note:  

  函数体中如果只有一行语句可以省略 {}

  方法可以省略返回值类型;Scala提供了强大的类型推断功能、以及使用类型推断的时候两个限制
  如果方法没有返回值可以使用Unit标注,类似于java的void 一旦方法使用了Unit 即使方法中有最后一条语句,也不返回。

 

 /*定义的方法没有使用return关键字*/
  def function1(param1: String, param2: String): String = {
    "[" + param1 + "]" + ",[" + param2 + "]"

  }

  /*定义的方法使用return关键字*/
  def function2(param1: String, param2: String): String = {

    return "[" + param1 + "]" + ",[" + param2 + "]"

  }

  println(function1("Hello", "World"))

}

/*函数体中如果只含有一条语句可以省略 {}*/
def function3(a: Int, b: Int): Int = if (a > b) a else b;

/*自动类型推断功能有两个限制*/
/*1、如果使用return 关键字指定返回值 那么必须指定返回值的类型 否则编译错误*/
def function4(a: Int, b: Int): Int = {

  if (a > b)
    return a
  else
    return b
}

//  def function5(a: Int, b: Int)= {
//
//    if (a > b)
//      return a
//    else
//      return b
//  }
println(function4(4, 6));

//  println(function5(4, 8));
//  2、函数的方法体中存在着递归调用 必须指定返回值类型
/*  def function6(x: Int, y: Int) = {

    if (x % y == 0)
      y
    else
      function6(y, x % y)
  }*/
//函数的返回值为空 
def function7(a: Int, b: Int): Unit = {

  if (a > b) {
    a
  } else {
    b
  }
}

print(function7(2, 3)) //()

2)spark开发中常用格式: def 方法名称:(参数列表类型)=>返回值类型={方法体中书写具体的参数名称}

def function8: (Int, Int, Int) => Int = {
  (x, y, z) => {
    x + y + z
  }
}

3)柯里化

1、有一个函数,原来接受两个参数

2、现在我们将这个两个参数拆开

3、这样我们就得到了两个一个参数的函数了

4、这样我们调用的时候,就需要分别传入两个参数了

5、这样就叫柯里化

有多个参数列表的函数就是柯里化函数,所谓的参数列表就是用小括号括起来的函数参数列表。

柯里化函数定义:

def sum(x:Int)(y:Int) = x + y
或者
def add(x:Int)=(y:Int) => x+y 

柯里化函数调用:add(1)(2)

//1) 函数的另一种定义方式:柯里化  def 函数名称(参数列表)(参数列表):返回值类型={函数体}
def function9(a: Int)(b: Int) = {
  a + b
}
//函数的调用
println(function9(2)(4))

//2) 柯里化的另一种格式
def function10(a: Int) = (b: Int) => {
  a + b
}
println(function10(2)(5))

4)可变参数的方法

Scala允许指定函数的最后一个参数可重复。 如 String* Int* 等。

//  可变参数的方法  当方法的参数个数不确定的时候 可以将方法的参数定义为可变的参数
//  可变的参数要求是方法的最后一个参数
   def function14(name:String,nums:Int*): Unit ={
     var sum=0
     for(num -> nums){
       sum+=num
     }
     println(name+"'"+"sum="+sum)

   }
  function14("yangshaojun",1,2,3,4,5)
def printString(args:String*)={
  var i=0
  for(arg <- args) {
    println("args's ["+i+"]"+"value is "+arg)
    i=i+1
  }
}

使用序列调用变长函数

val s=function14(1 to 5 ) 是错误的。此时需要使用scala的特殊语法定义序列,让scala解释器能够识别,这种语法非常有用;在scala对的源码中大量的使用。

val s=functionn14(1 to 5 :_*)

5)方法的参数的默认值和带参数名称调用

方法的参数列表中的变量可以在定义方法的时候就去给他一个默认值

方法在调用的时候,赋值往往是从左到右赋值,也就是说需要将默认值放在方法参数的右边。

方法在调用的时候还可以指定参数的名字,这样就可以不考虑方法的参数的顺序了。

//  方法的默认参数和指定参数名调用
def function15(name: String, age: Int = 12, sex: String = "Man"): Unit = {
  print("name=" + name + "  age=" + age + "  sex=" + sex)

}

//方法的调用从左到右赋值
//  指定参数名调用
function15(age = 15, name = "ysj", sex = "man")

函数定义注意点:

1)定义的方法 如果参数列表为空 那么在调用的时候可以加括号,也可以不加。

2)定义的方法 如果没有参数列表 那么在调用的时候不可以加括号。

3)没有返回值的方法 在参数列表括号后面直接添加方法体 我们称这种方法为过程。

//定义的方法 如果参数列表为空 那么在调用的时候可以加括号,也可以不加。
def function11() = {
  "hello world!"
}

print(function11())
print(function11)

//定义的方法 如果没有参数列表 那么在调用的时候不可以加括号。
def function12 = {
  println("function12")
}

//  print(function12()) 编译错误
print(function12)

//  没有返回值的方法 在参数列表括号后面直接添加方法体 我们称这种方法为过程。
def function13(a: Int, b: Int) {
  println(a + b)
}

函数的字面量(值函数)

在Scala语言中函数也是对象,也可以像变量一样被赋值,把这种函数称为函数字面量或者值函数。

1)通用定义格式: val 变量名=(参数列表)=>{函数体} 

    这里的变量名 即是方法名称也是方法返回值赋值给变量的变量名称。

val sum = (x: Int, y: Int) => {
  print(x + y)
  x + y
}
sum(2,5)

2)首先定义函数的参数列表类型,具体的函数参数在函数体中定义

/*首先定义函数的参数列表类型,具体的函数参数在函数体中定义*/
val sum2:(Int,Int,Int)=> Int={
  (x,y,z)=>{
    x+y+z
  }
}
sum2(1,2,3)

高阶函数

值函数的作用主要作为高阶函数的输入

常用的高阶函数 map 、flatMap、filter、reduce、fold

/*值函数的使用场景就是作为高阶函数的输入*/
val  arrInt=Array(1,2,3,4)
val increment=(x:Int)=>x+1
arrInt.map(increment)
/*实际应用中如果值函数只使用一次,常常直接作为函数参数*/
arrInt.map((x:Int)=>x+1)
//map的函数输入类型可以自动类型推断推断出来 可以省略
arrInt.map((x)=>x+1)
//map中的值函数(x)=>x+1 参数只有一个的时候可以将值函数的输入参数的括号去掉
arrInt.map(x=>x+1)
//值函数x=>x+1 的输入参数在符号 =>右边只出现一次可以用占位符 _ 对该值函数进一步简化
arrInt.map(_+1)
 /*1、 map的使用 def Map[B](f:(A)=>B):Array[B]
  * 将函数f作用于数组的所有元素,并返回一个新的数组 Array[B] f函数的输入类型为A 输出类型为B*/
  val arrString = Array("hive", "spark", "hadoop")
  arrString.map(_ * 2)
  // Array(hivehive, sparkspark, hadoophadoop)
  val arrInt = Array(1, 2, 3)
  arrInt.map(_ * 2) //Array(2, 4, 6)

  /*集合类型的map函数使用*/
  val listString=List("hive"->1,"spark"->2,"hadoop"->3)
  listString.map(x =>x._1)
  /*简化*/
  listString.map(_._1)

  /*Map类型的 map函数的使用*/
  val mapString=Map("hive"->1,"spark"->2,"hadoop"->3)
  mapString.map(x=>x._1)

  /*2、flatMap函数的使用
  * 将函数f作用于集合中所有的元素,各元素得到相应的集合 ,然后再将其扁平化返回 */
  val listInt=List(1,2,3)
  listInt.flatMap(x => x match {
    case 1 => List(1)
    case _=>List(x)
  }) //List(1, 2, 3)

  listInt.map(x => x match {
    case 1 => List(1)
    case _=>List(x*2)
  })//List(List(1), List(4), List(6))
 /*map和flatMap的区别就是 map是来几条数据出几条数据 flatMap是多条数据输入 输出一条*/

  /*reduce 数据的聚合 x+y的值作为下次的x */
  val arrReduce=Array(1,2,3)
  arrReduce.reduce((x:Int,y:Int)=>{println(x,y);x+y})
  arrReduce.reduce(_+_)
  /*filter函数的使用*/
  arrReduce.filter(x=>x>2)
  arrReduce.filter(_>2)
  /*fold函数
  * 使用联合二元算子对集合进行fold操作*/
  arrReduce.fold(0)((x: Int, y: Int) => {
    println(x, y);
    x + y
  })
  /*(0,1)
    (1,2)
    (3,3)
     res16: Int = 6*/
}

闭包

/*闭包
 *代码val f=(x:Int) =>x +i 定义了一个函数字面量,函数中使用自由变量i,
 * 变量i在程序的运行中会发生变化,处于开放的状态
  * 而当函数执行的时候,自由变量已经被确定下来,
  * 此时认为在运行的时候它暂时处于封闭的状态,
  * 这样由开放到封闭过程的函数称为闭包 */
var i = 15
val f = (x: Int) => x + i
f(10) //25
i = 25
f(10) //35

函数柯里化

 def 函数名称(参数列表)(参数列表):返回值类型={函数体}

def multiply(a: Int)(b: Int) = {
  a + b
}

println(multiply(2)(4))

部分应用函数

上面的柯里化函数其实是两个函数组成的一个函数。

multiply(10) 函数返回的其实是第二个函数。可以使用 下划线 "_"将返回的函数转为部分应用函数。

scala> val pal=multiply(10)_

pal: Int => Int = <function1>

 //调用部分应用函数 fal

scala> pal(50)

res13: Int = 60

两个参数都不指定的部分应用函数

scala> val pal2= multiply_

scala> pal2(10)(12)
res18: Int = 22

不只是柯里化函数有部分应用函数,普通的函数也有部分应用函数

//普通函数
scala> def product(x1:Int,x2:Int,x3:Int) = x1* x2 *x3
product: (x1: Int, x2: Int, x3: Int)Int
//一个参数的部分应用函数 product_1
scala> def product_1=product(_:Int,2,3)
product_1: Int => Int
//调用部分应用函数
scala> product_1(1)
res22: Int = 6
//两个参数的部分应用函数 product_2
scala>  def product_2=product(_:Int,_:Int,3)
product_2: (Int, Int) => Int
//调用部分应用函数
scala> product_2(2,3)
res0: Int = 18
//三个参数的部分应用函数 product_3
scala> def product_3=product(_:Int,_:Int,_:Int)
product_3: (Int, Int, Int) => Int
//调用部分应用函数
scala> product_3(10,20,30)
res2: Int = 6000
//三个参数的部分应用函数 等价于product(_:Int,_:Int,_:Int)
scala> def product_3=product _
product_3: (Int, Int, Int) => Int
//调用部分应用函数
scala> product_3(10,20,30)
res3: Int = 6000

 

Martin Odersky 用他定义的匹萨语言给了 Java世界一个很大的冲击。尽管匹萨本身没有流行 但它展现了当把面向对象函数型语言两种风格,技术地且很有品地混搭在一起时,就形成了 自然强有力的组合。匹萨的设计成为了 Java泛型的基础,马丁的 GJ(Generic Java)编译 Java 1.3开始成为了 Sun 微系统的标准编译器(尽管关闭了泛型)。我有幸能够维护这个编译 年,因此我能通过第一手经验从语言设计到语言的实现方面(向大家)报告马丁的技术。 那时候我们还在 Sun 公司,尝试用一些零打碎敲的特定问题解决方案来扩展语言,如 for-eac 环,枚举,自动装包,去简化程序开发的时候,马丁则继续着他在更强大的正交语言原语方面 作以帮助程序员用库来提供解决方案。 后来,静态类型语言受到了冲击。Java 的经验说明了静态语言编程会导致大量的固定写法的代 通常认为我们应该避免静态类型从而消除这种代码,于是人们对动态语言如 Python,Rub Groovy的兴趣开始增加。这种认知被马丁最近的作品,Scala,的出现打破。 Scala 是一种很有品味的类型语言:它是静态类型的,但仅在需要的地方显式定义类型。Scala 向对象函数式语言两方面获得了强大的特性,然后用一些新奇的点子把它们漂亮地整合成一 它的语法是如此的轻量级,而原语又如此富有表达力,以至于根本可以认为 API的使用不须负 法开销。我们可以在标准库中,如拆分器、组合器执行器,中发现例子。从这点上看,Scal 一种支持内嵌的域特化:embedded domain-specific 的语言。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值