前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Scala的函数

Scala的函数

作者头像
云飞扬
发布2018-05-11 13:49:54
1.3K0
发布2018-05-11 13:49:54
举报
文章被收录于专栏:星汉技术星汉技术

----------目录---------------------------------------------------------

1.Scala简介和安装

2.Scala语法介绍

3.Scala的函数

4.Scala中的集合类型

-------------------------------------------------------------------------------------------------------------

Scala的函数

1、函数的声明

    scala函数通过def关键字定义,def前面可以具有修饰符,可以通过private、protected来控制其访问权限。

    注意:没有public,不写默认就是public的。此外也可跟上override,final等关键字修饰。

1.格式

    [private/protected] def 函数名(参数列表):返回值声明 = {函数体}

2.函数的返回值

    1)函数体中return关键字往往可以省略掉,一旦省略掉,函数将会返回整个函数体中最后一行表达式的值,这也要求整个函数体的最后一行必须是正确类型的值的表达式。

    2)大部分时候scala都可以通过=符号来自动推断出返回值的类型,所以通常返回值类型声明可以省略。

    但是注意:如果因为省略了返回值类型造成歧义,则一定要写上返回值声明。

    3)如果函数体只有一行内容,则包裹函数体的大括号可以省略。

    4)如果返回值类型是UNIT,则另一种写法是可以去掉返回值类型和等号,把方法体写在花括号内,而这时方法内无论返回什么,返回值都是UNIT。相当于Java中的void。

    示例:

代码语言:javascript
复制
    //方法的返回值为空
    private def f1(){}
	protected def f2():String={"hello"}
	def f3()={"hello"}
	//如果函数体只一行内容,可以省了花括号
	def f4()="hello"
	//定义方法参数类型,返回值类型,及返回值
	def f5(a:Int,b:Int)={a+b}

3.默认参数

    可以为函数的参数设置默认值。

    示例:

代码语言:javascript
复制
	//默认参数的使用
	def f8(a:String,b:String="[",c:String="]")={
		b+a+c
	}

4.占位符

    占位符:占位符指的是scala中的下划线_ ,可以用它当作一个或多个参数来使用。

    使用_占位符的前提要求:每个参数在函数仅出现一次。

    使用下划线时,如果类型可以自动推断出,则不用声明类型。如果无法自动推断类型,则在下划线后自己来显示声明类型即可。

示例:

代码语言:javascript
复制
//要求通过reduceLeft函数计算阶乘结果
val a2=Array(1,2,3,4)
a2.reduceLeft{(a:Int,b:Int)=>{a*b}}
a2.reduceLeft{_*_}

2、函数的种类

    Scala中的函数分为成员函数、本地函数(内嵌在函数内的函数)、函数值(匿名函数)、高阶函数。

1.成员函数

    成员函数:函数被使用在类的内部,作为类的一份子,称为类的成员函数。

    示例:

代码语言:javascript
复制
class Person {
  //eat方法是Person的成员方法
  def eat() {
    println("eat")
  }
}

2.本地函数

    本地函数:函数内嵌的函数称为本地函数,这样的函数外界无法访问。

    示例:

代码语言:javascript
复制
class Person {
  //eat方法是Person的成员方法
  def eat() {
    println("eat")
    //本地函数:内嵌在函数内的函数。对象不能直接调用本地函数。
    def cook() {
      println("cook")
    }
  }
}

3.匿名函数

    函数值(匿名函数):

    1.匿名函数没有函数名。

    2.匿名函数的作用是配合高阶函数来使用的,匿名函数可以作为函数的参数进行传递。

    示例:

代码语言:javascript
复制
(a:Int,b:Int)=>{a+b}
(a:Int,b:Int)=>a+b
val a1=Array(1,2,3,4)
//a=1	b=2	a+b=3
//a=3	b=3	a+b=6
//a=6	b=4 a+b=10
a1.reduceLeft{(a:Int,b:Int)=>a+b}
a1.reduceLeft{(a,b)=>a+b}
a1.foreach{(x:Int)=>{println(x)}}
a1.foreach{x=>println(x)}

4.高阶函数

    高阶函数:函数可以作为方法的参数进行传递和调用。

    示例:

代码语言:javascript
复制
  //定义一个高阶函数,可以将函数当作参数传递
  def f2(a:Int,b:Int,f:(Int,Int)=>Int)={
  	f(a,b)
  }
  f2(2,3,(a:Int,b:Int)=>{a+b})
  f2(2,3,(a,b)=>a+b)
  f2(2,3,(a,b)=>a*b)
  f2(2,3,_*_)
  //定义一个高阶函数,要求:传入一个String类型的参数,以及一个处理String类型的匿名函数
  //此高阶函数的返回值就是匿名函数的返回值
  def f3(a:String,f:(String)=>Array[String])={
  	f(a)
  }
  //注意:匿名函数一定要和指定返回值类型匹配
  f3("hello,world",(a:String)=>{a.split(",")})
  f3("hello,world",a=>a.split(","))
  f3("hello,world",a=>a split ",")
  f3("hello,world",_.split(","))
  //要求通过reduceLeft函数计算阶乘结果
  val a2=Array(1,2,3,4)
  a2.reduceLeft{(a:Int,b:Int)=>{a*b}}

3、递归

    想要实现递归方法,有两个要素可以快速的实现。

    要素1:找出递归结束的条件。

    要素2:找出函数的映射关系。

    scala中,如果在递归时,保证函数体的最后一行为递归调用,则称这样的递归为尾递归。scala会针对尾递归做优化处理,所以建议在写递归时写成尾递归形式。

    范例:

    斐波那契数列:1 1 2 3 5 8 13 ?

    要素1:找出递归结束的条件:f(n)=f(n-1)+f(n-2)

    要素2:找出函数的映射关系:f(0)=1;f(1)=1

    所以代码就可以为:

代码语言:javascript
复制
  def f1(n:Int):Int={
  	if(n==0)return 1
  	if(n==1)return 1
  	else f1(n-1)+f1(n-2)
}

    示例:

代码语言:javascript
复制
  //从1开始做加法,只加偶数,当加和累计超过50时,结束递归
  //示意:2+4+6……
  def f1(num: Int, sum: Int): Int = {
    if (sum > 50) return sum;
    if (num % 2 == 0) { f1(num + 1, sum + num) }
    else { f1(num + 1, sum) }
  }

  //2 3 4 9 8 27 16 ?
  //f(n)= f(n-2)*2
  //f(n)=f(n-2)*3
  //f(0)=2;f(1)=3
  def f2(n: Int): Int = {
    if (n == 0) return 2
    if (n == 1) return 3
    if (n % 2 == 0) return f2(n - 2) * 2
    else f2(n - 2) * 3
  }

  //2 3 4 9 16 81 ?
  // n的取值:f(0) f(1) f(2)  f(3)  f(4) f(5)
  //当n为偶数时,f(n)=f(n-2)*f(n-2)
  //当n为奇数是,f(n)=f(n-2)*f(n-2)
  //fn=f(n-2)*f(n-2)
  def f3(n: Int): Int = {
    if (n == 0) return 2
    if (n == 1) return 3
    else f3(n - 2) * f3(n - 2)
  }

  //求 1~n的数字之和
  //1    3      6     10     15
  //f(0) f(1)  f(2)   f(3)   f(4)
  //f(n)=f(n-1)+n+1
  def f5(n: Int): Int = {
    if (n == 0) return 1
    else f5(n - 1) + n + 1
  }

  //给定一个初始值n,并设定sum的初始值为0,当求和sum>12时结束递归
  //0  1  3   6   10  15
  //f(0,0)——n=0,sum=0
  //f(1,1)——n=1,sum=1
  //f(2,3)——n=2,sum=3
  //f(3,6)——n=3,sum=6
  //f(n+1,sum+n)
  def f6(n: Int, sum: Int): Int = {
    if (sum > 12) return sum
    else f6(n + 1, sum + n)
  }

  //给定一个scope范围,计算0~scope范围的整数之和,
  //当和>12或者达到scope边界时,结束递归
  def f7(n: Int, sum: Int, scope: Int): Int = {
    if (sum > 12) return sum
    if (n - 1 == scope) return sum
    else f7(n + 1, sum + n, scope)
  }

4、变长参数

    在scala中,可以指明函数的最后一个参数是重复的。从而允许客户向函数传入可变参数的列表。

    想要标注一个重复参数,可以在参数的类型之后放一个星号。重复参数(可变参数)的类型是声明参数类型的数组。

    示例:

代码语言:javascript
复制
  //定义变长参数
  def f1(num:Int*)={}
  def f2(num:Int*)={
  	for(i<-num)println(i)
  }
  f2(1,2,3,4,5)
  def f21(a:Int,str:String*)={}

5、柯里化 Currying

1.介绍

    scala的柯里化的作用是结合scala的高阶函数,从而允许用户自建立控制结构。

    柯里化(Currying)技术 Christopher Strachey 以逻辑学家 Haskell Curry 命名的(尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的)。它是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。

案例

代码语言:javascript
复制
    //首先我们定义一个函数:
    def f1(a:Int,b:Int):Int={a+b}
    //现在我们把这个函数变一下形:
    def f2(a:Int)(b:Int)={a+b}
    //那么我们应用的时候,应该是这样用:f2(2)(3),最后结果都一样是5,这种方式(过程)就叫柯里化。
    val r1=f2(2)(3)
    //柯里化实质上会演变成这样一个函数:
    //接收一个参数a,返回一个匿名函数,
    //该匿名函数又接收一个参数b,函数体为a+b
    def f3(a:Int)=(b:Int)=>a+b
    val f4=f3(2)
    //请思考 f4(3)的值是多少?答案是:5
    f4(3)

示例

代码语言:javascript
复制
  //柯里化
  def f3(a:Int,b:Int)={a+b}
  def f31(a:Int)(b:Int)={a+b}
  f3(2,3)
  f31(2)(3)

  def f4(a:Int,b:Int,c:Int)={a+b+c}
  def f41(a:Int)(b:Int)(c:Int)={a+b+c}
  def f42(a:Int,b:Int)(c:Int)={a+b+c}
  def f43(a:Int)(b:Int,c:Int)={a+b+c}

  def f5(a:Int,b:Int,f:(Int,Int)=>Int)={f(a,b)}
  def f51(a:Int)(b:Int,f:(Int,Int)=>Int)={f(a,b)}
  def f52(a:Int,b:Int)(f:(Int,Int)=>Int)={f(a,b)}
  def f53(a:Int)(b:Int)(f:(Int,Int)=>Int)={f(a,b)}
  f5(2,3,_+_)
  f52(2,3)(_+_) 

4.作用

    柯里化技术在提高适用性、延迟执行或者固定易变因素等方面有着重要重要的作用,加上scala语言本身就是推崇简洁编码,使得同样功能的函数在定义与转换的时候会更加灵活多样。另外在Spark的源码中有大量运用scala柯里化技术的情况,需要掌握好该技术才能看得懂相关的源代码。

    在scala柯里化中,闭包也发挥着重要的作用。所谓的闭包就是变量出了函数的定义域外在其他代码块还能其作用,这样的情况称之为闭包。就上述讨论的案例而言,如果没有闭包作用,那么转换后函数其实返回的匿名函数是无法在与第一个参数a相关结合的,自然也就无法保证其所实现的功能是跟原来一致的。

6、内置高阶函数

    适用于所有集合。

1.partition

    拆分,将一个集合按一个布尔值分成两个集合,满足条件的一个集合,其他另外一个集合。

    按照指定原则拆分,返回的是一个二元Tuple。

代码语言:javascript
复制
  val l1=List(1,2,3,4,5,6)
  l1.partition{x=> x%2==0}
//> res0: (List[Int], List[Int]) = (List(2, 4, 6),List(1, 3, 5))

2.map

    映射,把一个集合转换为另外一个集合。集合中元素个数不变。

    改变集合类型中,元素的形式或数据,返回一个新的集合。此方法不会改变集合中元素的个数,只是改变了数值和形式。

代码语言:javascript
复制
  val l2=List("hadoop","world","hello","hello")
  l2.map(x=>(x,1))
//> res1: List[(String, Int)] = List((hadoop,1), (world,1), (hello,1), (hello,1))
  val l3=List("hello word","hello hadoop")
  l3.map{x=>x.split(" ")}
//> res2: List[Array[String]] = List(Array(hello, word), Array(hello, hadoop))

3.flatMap

    扁平化map,会取出集合的元素。注意,此方法会改变集合中的元素个数。

    一般引用场景:读取文件后,处理文件,将每行数据按指定分割符切分。

代码语言:javascript
复制
  l3.flatMap{x=>x.split(" ")}
//> res3: List[String] = List(hello, word, hello, hadoop)
  //要求:操作l3将其变成(word,1)的形式
l3.flatMap{x=>x.split(" ")}.map(x=>(x,1))
//> res4: List[(String, Int)] = List((hello,1), (word,1), (hello,1), (hadoop,1))

4.filter

    过滤。

代码语言:javascript
复制
  val l4=List(1,2,3,4,5)
  l4.filter(x=>x>3)
//> res5: List[Int] = List(4, 5)

5.reduce

    归约,reduce的过程:将上次的运行结果和下一个值进行运算。

    函数接收两个参数 => 返回一个值。

    等价于reduceLeft。

代码语言:javascript
复制
l4.reduce{_+_}
//> res6: Int = 15

6.groupBy

    按指定规则做聚合,最后将结果返回到一个map映射里。

    按照指定原则做分组,返回的是Map类型。Map的key是分组键,value是对应的List集合。

代码语言:javascript
复制
val l5=List(("bj",1),("sh",2),("bj",3),("sh",4),("sz",5))
l5.groupBy{x=>x._1}
//> res7: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(bj ->List((bj,1), (bj,3)), sz -> List((sz,5)), sh -> List((sh,2), (sh,4)))
l5.groupBy{case(addr,count)=>addr}
//> res8: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(bj ->List((bj,1), (bj,3)), sz -> List((sz,5)), sh -> List((sh,2), (sh,4)))

7.mapValues

    此方法是针对的Map类型的值做操作,此方法只适用于Map类型。

代码语言:javascript
复制
  val m1=Map("rose"->23,"tom"->25,"jary"->30)
  m1.mapValues {x=>x+10}
//> res9: scala.collection.immutable.Map[String,Int] = Map(rose -> 33, tom -> 35, jary -> 40)

8.sortBy

    排序。

代码语言:javascript
复制
  val l6=List((2,"aaa"),(1,"bbb"),(4,"ddd"),(3,"ccc"))
  l6.sortBy{x=>x._1}
//> res10: List[(Int, String)] = List((1,bbb), (2,aaa), (3,ccc), (4,ddd))
  l6.sortBy{x=>x._2}
//> res11: List[(Int, String)] = List((2,aaa), (1,bbb), (3,ccc), (4,ddd))
  l6.sortBy{case(num,str)=>num}
//> res12: List[(Int, String)] = List((1,bbb), (2,aaa), (3,ccc), (4,ddd))

案例:统计单词频率

    统计出每个单词出现的频次。最后的结果形式:(hello,5)(hadoop,2)……

代码语言:javascript
复制
val l7=List("hello hadoop","hello world","hello spark","hello hadoop","hello hive")
//方法一:
  l7.flatMap{line=>line.split(" ")}.groupBy{word=>word}.mapValues { list => list.size }.foreach{println(_)}
//方法二:
  l7.flatMap { line => line.split(" ") }.map { word => (word,1) }.groupBy(x=>x._1).mapValues{list=>list.size}.foreach{println(_)}
//方法三:
  l7.flatMap { line => line.split(" ") }.map { word => (word,1) }.groupBy(x=>x._1).mapValues{list=>list.map(x=>x._2).reduce(_+_)}.foreach{println(_)}
//简化写法:
  l7.flatMap{_.split(" ")}.map{(_,1)}.groupBy(_._1).mapValues{_.map(_._2).reduce(_+_)}.foreach{println(_)}
//要求统计单词频次,然后返回频次最高的前2项结果
  l7.flatMap { line => line.split(" ") }.map { word => (word,1) }.groupBy(x=>x._1).mapValues{list=>list.map(x=>x._2).reduce(_+_)}.toList.sortBy(x=> -x._2).take(2)
//> res13: List[(String, Int)] = List((hello,5), (hadoop,2))

上一篇:Scala语法介绍

下一篇:Scala中的集合类型

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ----------目录---------------------------------------------------------
  • Scala的函数
    • 1、函数的声明
      • 1.格式
      • 2.函数的返回值
      • 3.默认参数
      • 4.占位符
    • 2、函数的种类
      • 1.成员函数
      • 2.本地函数
      • 3.匿名函数
      • 4.高阶函数
    • 3、递归
      • 4、变长参数
        • 5、柯里化 Currying
          • 1.介绍
          • 案例
          • 示例
          • 4.作用
        • 6、内置高阶函数
          • 1.partition
          • 2.map
          • 3.flatMap
          • 4.filter
          • 5.reduce
          • 6.groupBy
          • 7.mapValues
          • 8.sortBy
          • 案例:统计单词频率
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档