欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Scala详细文本教学04

程序员文章站 2022-06-14 17:00:36
...

前言

你们好我是啊晨,前些天偷懒了下
首先呢还是那句话,内容很多,分为几篇这是最后篇,选择阅读就好,很详细。
下面请:

一、Scala 方法

Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。
Scala 中的方法跟 Java 的类似,方法是组成类的一部分。
Scala 中使用 val 语句可以定义函数,def 语句定义方法。

class Test{
  def m(x: Int) = x + 3
  val f = (x: Int) => x + 3
}

注意:有些翻译上函数(function)与方法(method)是没有区别的。

1、方法声明

Scala 方法声明格式如下:

def methodName ([参数列表]): [return type]={方法体}

如果你不写等于号和方法主体,那么方法会被隐式声明为抽象(abstract),包含它的类型于是也是一个抽象类型。

2、方法定义

方法定义由一个 def 关键字开始,紧接着是可选的参数列表,一个冒号 : 和方法的返回类型,一个等于号 = ,最后是方法的主体。
Scala 方法定义格式如下:

def methodName ([参数列表]) : [return type] = {
   method body
   return [expr]
}

以上代码中 return type 可以是任意合法的 Scala 数据类型。参数列表中的参数可以使用逗号分隔。
以下方法的功能是将两个传入的参数相加并求和:

object add{
   def addInt( a:Int, b:Int ) : Int = {
      var sum:Int = 0
      sum = a + b
      return sum
   }
}

如果方法没有返回值,可以返回为 Unit,这个类似于 Java 的 void, 实例如下:

object Hello{
   def printMe( ) : Unit = {
      println("Hello, Scala!")
   }
}

3、方法调用

Scala 提供了多种不同的方法调用方式:
以下是调用方法的标准格式:

methodName( 参数列表 )

如果方法使用了实例的对象来调用,我们可以使用类似java的格式 (使用 . 号):

[instance.]mehtodName( 参数列表 )

以上实例演示了定义与调用方法的实例:

object Test {
   def main(args: Array[String]) {
        println( "Returned Value : " + addInt(5,7) );
   }
   def addInt( a:Int, b:Int ) : Int = {
      var sum:Int = 0
      sum = a + b
      return sum
   }
}

执行以上代码,输出结果为:

$ scalac Test.scala 
$ scala Test
Returned Value : 12

二、函数

Scala 也是一种函数式语言,所以函数是 Scala 语言的核心。以下一些函数概念有助于我们更好的理解 Scala 编程:

函数传名调用(Call-by-Name) 指定函数参数名
函数 - 可变参数 递归函数
默认参数值 高阶函数
内嵌函数 匿名函数
偏应用函数 函数柯里化(Function Currying)

1、方法和函数的区别

1、函数可作为一个参数传入到方法中,而方法不行。

Scala详细文本教学04

object MethodAndFunctionDemo {
  //定义一个方法
  //方法m2参数要求是一个函数,函数的参数必须是两个Int类型
  //返回值类型也是Int类型
  def m1(f:(Int,Int) => Int) : Int = {
    f(2,6)
  }

  //定义一个函数f1,参数是两个Int类型,返回值是一个Int类型
  val f1 = (x:Int,y:Int) => x + y
  //再定义一个函数f2
  val f2 = (m:Int,n:Int) => m * n

  //main方法
  def main(args: Array[String]): Unit = {
    //调用m1方法,并传入f1函数
    val r1 = m1(f1)
    println(r1)
    //调用m1方法,并传入f2函数
    val r2 = m1(f2)
    println(r2)
  }
}

运行结果:

8
12 

2、在Scala中无法直接操作方法,如果要直接操作方法,必须先将其转换成函数。有两种方法可以将方法转换成函数:

val f1 = m _

在方法名称m后面紧跟一个空格和下划线告诉编译器将方法m转换成函数,而不是要调用这个方法。 也可以显示地告诉编译器需要将方法转换成函数:

val f1: (Int) => Int = m

通常情况下编译器会自动将方法转换成函数,例如在一个应该传入函数参数的地方传入了一个方法,编译器会自动将传入的方法转换成函数。
Scala详细文本教学04

object TestMap {

  def ttt(f:Int => Int):Unit = {
    val r = f(10)
    println(r)
  }

  val f0 = (x : Int) => x * x

  //定义了一个方法
  def m0(x:Int) : Int = {
    //传递进来的参数乘以10
    x * 10
  }

  //将方法转换成函数,利用了神奇的下滑线
  val f1 = m0 _

  def main(args: Array[String]): Unit = {
    ttt(f0)

    //通过m0 _将方法转化成函数
    ttt(m0 _);

    //如果直接传递的是方法名称,scala相当于是把方法转成了函数
    ttt(m0)

    //通过x => m0(x)的方式将方法转化成函数,这个函数是一个匿名函数,等价:(x:Int) => m0(x)
    ttt(x => m0(x))
  }
}

输出结果为:

100
100
100
100

3、函数必须要有参数列表,而方法可以没有参数列表
Scala详细文本教学04
4、在函数出现的地方我们可以提供一个方法
在需要函数的地方,如果传递一个方法,会自动进行ETA展开(把方法转换为函数)
Scala详细文本教学04
Scala详细文本教学04

如果我们直接把一个方法赋值给变量会报错。如果我们指定变量的类型就是函数,那么就可以通过编译,如下:
Scala详细文本教学04
当然我们也可以强制把一个方法转换给函数,这就用到了 scala 中的部分应用函数:
Scala详细文本教学04

2、scala 匿名函数

Scala 中定义匿名函数的语法很简单,箭头左边是参数列表,右边是函数体。
使用匿名函数后,我们的代码变得更简洁了。
下面的表达式就定义了一个接受一个Int类型输入参数的匿名函数:

//var 函数名称 = (参数) => 函数体
var inc = (x:Int) => x+1
//var 函数名称 = (参数) => 函数体
//函数体中最后一个表达式是函数的返回值
var add4 = (x:Int,name:String) =>{
  x+name
  "woshililei"
}
//无参函数
val f4 =()  =>{
  1
}
//调用无参函数,后面括号不能丢
val res04 = f4()
//不加括号,表示调用函数的toString方法
val res05 = f4

上述定义的匿名函数,其实是下面这种写法的简写:

//第一个Int是入参类型,第二个Int是返回值类型
//Function1后面的数字是入参的个数
def add2 = new Function1[Int,Int]{  
    def apply(x:Int):Int = x+1;  
}
//第一个Int是入参类型,第一个String是入参类型,第二个String是返回值类型
def add3 = new Function2[Int,String,String] {
  def apply(x:Int,y:String):String = x+y;
}
val f5 = new Function0[Int] {
  def apply(): Int ={
    12
  }
}

以上实例的 inc 现在可作为一个函数,使用方式如下:

var x = inc(7)-1

还有一种非常轻量级的方式来写函数类型。下面是上面定义的三个函数的类型:

Int => Int
(Int, Int) => String
() => String

这个语法是下面类型的简写:

Function1[Int, Int]
Function2[Int, Int, String]
Function0[String]

同样我们可以在匿名函数中定义多个参数:

var mul = (x: Int, y: Int) => x*y

mul 现在可作为一个函数,使用方式如下:

println(mul(3, 4))

我们也可以不给匿名函数设置参数,如下所示:

var userDir = () => { System.getProperty("user.dir") }

userDir 现在可作为一个函数,使用方式如下:

println( userDir())

实例

object Demo {
   def main(args: Array[String]) {
      println( "multiplier(1) value = " +  multiplier(1) )
      println( "multiplier(2) value = " +  multiplier(2) )
   }
   var factor = 3
   val multiplier = (i:Int) => i * factor
}

将以上代码保持到 Demo.scala 文件中,执行以下命令:

$ scalac Demo.scala
$ scala Demo

输出结果为:

multiplier(1) value = 3
multiplier(2) value = 6

3、scala 递归函数

递归函数在函数式编程的语言中起着重要的作用。
Scala 同样支持递归函数。
递归函数意味着函数可以调用它本身,这个时候需要明确的指定返回值的类型。
以上实例使用递归函数来计算阶乘:

object Test {
   def main(args: Array[String]) {
      for (i <- 1 to 10)
         println(i + " 的阶乘为: = " + factorial(i) )
   }
   def factorial(n: BigInt): BigInt = { 
      if (n <= 1)
         1 
      else 
      n * factorial(n - 1)
   }
}

4、scala 高阶函数

高阶函数(Higher-Order Function)就是操作其他函数的函数。
Scala 中允许使用高阶函数, 高阶函数可以使用其他函数作为参数,或者使用函数作为输出结果。
以下实例中,apply() 函数使用了另外一个函数 f 和 值 v 作为参数,而函数 f 又调用了参数 v:

object TestDemo7 {
  //定义了一个匿名函数f1 入参还是Int类型 出参也是Int类型
  var f1 = (x:Int) => x+1
  //定义了一个匿名函数f2,入参是(一个函数f1),返回值是函数体内的最后一个表达式
  //f1是参数,它是个函数:Int是入参类型 => Int是出参类型
  //f1:Int => Int
  var f2 = (f1:Int=>Int)=>{
    f1(1)+123
  }

  //定义了一个匿名函数f3,入参是(一个函数,一个Int类型的值)
  //f1是第一个参数,它是个函数:Int是入参类型 => Int是出参类型
  //f1:Int => Int
  //y是第二个参数,它的类型是Int
  def f3 = (f1:Int => Int,y:Int)  => {
    //函数体f1函数有个固定的入参
  //    f1(1)+y
    //函数 y作为了f1函数的参数
    f1(y)
  }


  def main(args: Array[String]): Unit = {
    var resutl01 = f1(1)
    println(resutl01)
    //f2函数中调用f1函数,f1后面不能有括号
    var resutl02 = f2(f1)
    println(resutl02)

    var result103 = f3(f1,3)
    println(resutl02)
  }
}

5、Scala 函数嵌套

我们可以在 Scala 函数内定义函数,定义在函数内的函数称之为局部函数。
以下实例我们实现阶乘运算,并使用内嵌函数:
局部函数有作用域,作用的范围是定义局部函数开始到所在的代码块结束

object Test {
   def main(args: Array[String]) {
      println( factorial(0) )
      println( factorial(1) )
      println( factorial(2) )
      println( factorial(3) )
   }

   def factorial(i: Int): Int = {
      def fact(i: Int, accumulator: Int): Int = {
         if (i <= 1)
            accumulator
         else
            fact(i - 1, i * accumulator)
      }
      fact(i, 1)
   }
}

执行以上代码,输出结果为:

$ scalac Test.scala
$ scala Test
1
1
2
6

6、Scala 函数柯里化(Currying)

柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数, 并且返回接受余下的参数而且返回新函数的技术。
柯里化(Currying)指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。
实例
首先我们定义一个函数:

def add(x:Int,y:Int)=x+y

那么我们应用的时候,应该是这样用:add(1,2)
现在我们把这个函数变一下形:

def add(x:Int)(y:Int) = x + y

那么我们应用的时候,应该是这样用:add(1)(2),最后结果都一样是3,这种方式(过程)就叫柯里化。
实现过程
add(1)(2) 实际上是依次调用两个普通函数(非柯里化函数),第一次调用使用一个参数 x,返回一个函数类型的值,第二次使用参数y调用这个函数类型的值。
实质上最先演变成这样一个方法:

def add(x:Int)=(y:Int)=>x+y

那么这个函数是什么意思呢? 接收一个x为参数,返回一个匿名函数,该匿名函数的定义是:接收一个Int型参数y,函数体为x+y。现在我们来对这个方法进行调用。

val result = add(1)
返回一个result,那result的值应该是一个匿名函数:(y:Int)=>1+y
所以为了得到结果,我们继续调用result。
val sum = result(2)
最后打印出来的结果就是3

完整实例
下面是

object cury_func {
  def plainOldSum(x:Int,y:Int)= x + y  //非柯里化函数定义
  def curriedSum(x:Int)(y:Int)= x + y  //柯里化使用多个参数列表

  def main(args:Array[String]): Unit ={
    println(plainOldSum(1,5))
    println(curriedSum(1)(5))
    /*当你调用curriedSum (2)(8)时,实际上是依次调用两个普通函数(非柯里化函数), 第一次调用使用一个参数x,返回一个函数类型的值,第二次使用参数y调用这个函数类型的值*/
    //等价于:
    def first(x:Int) = (y:Int)=> x+y
    val second=first(2) //柯里化函数调用过程
    println(second)
    val res=second(8)
    println(res)
    //通过柯里函数curriedSum定义变量
    val onePlus=curriedSum(1)_ //_ 第二个参数列表的占位符,
    println(onePlus(2)) //传入的是第二个参数
  }
}
object Demo5 {
  def main(args: Array[String]): Unit = {
    val res1 = add01(1,2)
    println("res1 = "+res1)
    val res2 = add02(1)
    println("res2 = "+res2)
    val res3 = res2(2)
    println("res3 = "+res3)
  }

//  val f = (x:Int,y:Int,z:Int) => x+y+z
  //  val f1 = (x:Int) =>x
  //  val f2 = (y:Int,z:Int) => y+z
  val add01 = (x:Int,y:Int) => x+y
  //(x:Int) => (y:Int) =>x+y 整体表示一个函数
  // (y:Int) =>x+y 函数体中又包含一个函数
  val add02 = (x:Int) => (y:Int) =>x+y
}

三、隐式转换、隐式值

摘要:
通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码。

使用方式:
1.将方法或变量标记为implicit
2.将方法的参数列表标记为implicit
3.将类标记为implicit

Scala支持两种形式的隐式转换:
隐式值:用于给方法提供参数
隐式视图:用于类型间转换或使针对某类型的方法能调用成功

1、隐式值
例1:声明person方法。其参数为name,类型String

scala> def person(implicit name : String) = name   //name为隐式参数
person: (implicit name: String)String

直接调用person方法

scala> person
<console>:9: error: could not find implicit value for parameter name: String
              person
              ^

报错!编译器说无法为参数name找到一个隐式值
定义一个隐式值后再调用person方法

scala> implicit val p = "mobin"   //p被称为隐式值
p: String = mobin
scala> person
res1: String = mobin

因为将p变量标记为implicit,所以编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺省参数。
但是如果此时你又在REPL中定义一个隐式变量,再次调用方法时就会报错

scala> implicit val p1 = "mobin1"
p1: String = mobin1
scala> person
<console>:11: error: ambiguous implicit values:
 both value p of type => String
 and value p1 of type => String
 match expected type String
              person
              ^

匹配失败,所以隐式转换必须满足无歧义规则,在声明隐式参数的类型是最好使用特别的或自定义的数据类型,不要使用Int,String这些常用类型,避免碰巧匹配

2、隐式视图

class Person {
  var ticketType ="普通票"
  var ticketPrice=100
}
class Student {
  val ticketType ="学生票"
  val ticketPrice=50
}
class OlderMan {
  val ticketType ="老年票"
  val ticketPrice=75
}
object SpeciaTicketDemo {
  implicit def objectToSpecialPerson(obj: Object):Person={
    if(obj.isInstanceOf[Student]){
      var s = obj.asInstanceOf[Student]
      var p = new Person()
      p.ticketPrice=s.ticketPrice
      p.ticketType=s.ticketType
      p
    }else if(obj.isInstanceOf[OlderMan]){
      var o = obj.asInstanceOf[OlderMan]
      new Person
      var p = new Person()
      p.ticketPrice=o.ticketPrice
      p.ticketType=o.ticketType
      p
    }else{
      var p = obj.asInstanceOf[Person]
      p
    }
  }

  def bySpeciaTicket(person:Person): Unit ={
println("类型是"+person.ticketType+"票价是"+person.ticketPrice)
  }

  def main(args: Array[String]): Unit = {
    val p = new Person
    val s = new Student
    val o = new OlderMan
    bySpeciaTicket(p)
    bySpeciaTicket(s)
    bySpeciaTicket(o)
  }
}

隐式转换为目标类型:把一种类型自动转换到另一种类型
例2:将整数转换成字符串类型:

scala> def foo(msg : String) = println(msg)
foo: (msg: String)Unit
 
scala> foo(10)
<console>:11: error: type mismatch;
found : Int(10)
required: String
foo(10)
^

显然不能转换成功,解决办法就是定义一个转换函数给编译器将int自动转换成

String
scala> implicit def intToString(x : Int) = x.toString
intToString: (x: Int)String
 
scala> foo(10)
10

隐式转换调用类中本不存在的方法
例3:通过隐式转换,使对象能调用类中本不存在的方法

class SwingType{
  def  wantLearned(sw : String) = println("兔子已经学会了"+sw)
}
object swimming{
  implicit def learningType(s : AminalType) = new SwingType
}
class AminalType
object AminalType extends  App{
  import com.mobin.scala.Scalaimplicit.swimming._
  val rabbit = new AminalType
    rabbit.wantLearned("breaststroke")         //蛙泳
}

编译器在rabbit对象调用时发现对象上并没有wantLearning方法,此时编译器就会在作用域范围内查找能使其编译通过的隐式视图,找到learningType方法后,编译器通过隐式转换将对象转换成具有这个方法的对象,之后调用wantLearning方法

可以将隐式转换函数定义在伴生对象中,在使用时导入隐式视图到作用域中即可(如例4的learningType函数)

还可以将隐式转换函数定义在凶对象中,同样在使用时导入作用域即可,如例4
例4:

class SwingType{
  def  wantLearned(sw : String) = println("兔子已经学会了"+sw)
}

package swimmingPage{
object swimming{
  implicit def learningType(s : AminalType) = new SwingType  //将转换函数定义在包中
  }
}
class AminalType
object AminalType extends  App{
  import com.mobin.scala.Scalaimplicit.swimmingPage.swimming._  //使用时显示的导入
  val rabbit = new AminalType
    rabbit.wantLearned("breaststroke")         //蛙泳
}

像intToString,learningType这类的方法就是隐式视图,通常为Int => String的视图,定义的格式如下:
implicit def originalToTarget ( : OriginalType) : TargetType
其通常用在于以两种场合中:
1.如果表达式不符合编译器要求的类型,编译器就会在作用域范围内查找能够使之符合要求的隐式视图。如例2,当要传一个整数类型给要求是字符串类型参数的方法时,在作用域里就必须存在Int => String的隐式视图

2.给定一个选择e.t,如果e的类型里并没有成员t,则编译器会查找能应用到e类型并且返回类型包含成员t的隐式视图。如例3

四、常用函数

1、map函数和flatMap函数

在spark中map函数和flatMap函数是两个比较常用的函数。其中
map:对集合中每个元素进行操作。 map将一个函数应用于列表的每一个元素并且将其作为一个新的列表返回
flatMap:对集合中每个元素进行操作然后再扁平化。 flatMap应用于每个序列元素会返回包含原始列表所有序列内的元素的列表
理解扁平化可以举个简单例子

val arr=Array(("A",1),("B",2),("C",3))
arr.flatMap(x=>(x._1+x._2)).foreach(println)

输出结果为

A
1
B
2
C
3

如果用map

arr.map(x=>(x._1+x._2)).foreach(println)

输出结果

A1
B2
C3

2、zip函数

zip函数合并两个列表:

scala> val list = "Hello.World".toCharArray
list: Array[Char] = Array(H, e, l, l, o, ., W, o, r, l, d)
 
scala> val list1 = 1 to 20 toList
list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
 
scala> list.zip(list1)
res30: Array[(Char, Int)] = Array((H,1), (e,2), (l,3), (l,4), (o,5), (.,6), (W,7), (o,8), (r,9), (l,10), (d,11))
 
scala> list1.zip(list)
res31: List[(Int, Char)] = List((1,H), (2,e), (3,l), (4,l), (5,o), (6,.), (7,W), (8,o), (9,r), (10,l), (11,d))

返回的列表长度取决于较短的列表,只要有一个列表到达了末尾zip函数就停止了。我们可以使用zipAll函数来对较长列表的剩余元素进行处理:

scala> list.zipAll(list1,'a','1')
res33: Array[(Char, AnyVal)] = Array((H,1), (e,2), (l,3), (l,4), (o,5), (.,6), (W,7), (o,8), (r,9), (l,10), (d,11), (a,12), (a,13), (a,14), (a,15), (a,16), (a,17), (a,18), (a,19), (a,20))

(注:最后一个参数为1,让返回类型是Array[(Char,Int)]对于这个例子更好点)
如果字母的列表比较短,那么用’a’来补充,反之用1来补充。最后一个要介绍的zip函数是zipWithIndex。就像他的名字一样,元素的下标(从0开始)会被增加进去:

scala> list.zipWithIndex
res36: Array[(Char, Int)] = Array((H,0), (e,1), (l,2), (l,3), (o,4), (.,5), (W,6), (o,7), (r,8), (l,9), (d,10))

3、reduce函数

使用reduce我们可以处理列表的每个元素并返回一个值。通过使用reduceLeft和reduceRight我们可以强制处理元素的方向。(使用reduce方向是不被保证的)
注:reduce和fold很像,但reduce返回的值的类型必须和列表的元素类型相关(类型本身或其父类),但fold没有这种限制(但与此同时fold必须给定一个初始值),可以说reduce是fold的一种特殊情况。

scala> list1
res51: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
 
scala> val sum = (x:Int, y:Int) => {println(x,y) ; x + y}
sum: (Int, Int) => Int = <function2>
 
scala> list1.reduce(sum)
(1,2)
(3,3)
(6,4)
(10,5)
(15,6)
(21,7)
(28,8)
(36,9)
(45,10)
(55,11)
(66,12)
(78,13)
(91,14)
(105,15)
(120,16)
(136,17)
(153,18)
(171,19)
(190,20)
res52: Int = 210
 
scala> list1.reduceLeft(sum)
(1,2)
(3,3)
(6,4)
(10,5)
(15,6)
(21,7)
(28,8)
(36,9)
(45,10)
(55,11)
(66,12)
(78,13)
(91,14)
(105,15)
(120,16)
(136,17)
(153,18)
(171,19)
(190,20)
res53: Int = 210
 
scala> list1.reduceRight(sum)
(19,20)
(18,39)
(17,57)
(16,74)
(15,90)
(14,105)
(13,119)
(12,132)
(11,144)
(10,155)
(9,165)
(8,174)
(7,182)
(6,189)
(5,195)
(4,200)
(3,204)
(2,207)
(1,209)
res54: Int =210

4、foreach

Scala中的集合对象都有foreach和map两个方法。两个方法的共同点在于:都是用于遍历集合对象,并对每一项执行指定的方法。而两者的差异在于:foreach无返回值(准确说返回void),map返回集合对象。见如下代码及运行结果:b.getClass 得到的是void, 而c.getClass得到的是colletion 。再看代码的第9-11行,foreach和map的运行结果一致。结论就是:foreach 无法代替map. 而map方法却可以代替foreach。
问题:为什么scala提供foreach和map两个方法呢?本人看法是scala做为一种支持函数式编程范式的语言,必然要引入一种机制以支持数学中函数概念,而在数学中函数就是映射,所以scala中有map方法一点都不奇怪。而foreach只是用在不需要对集合执行映射操作,但需要遍历集合时才用到。总而言之,foreach用于遍历集合,而map用于映射(转换)集合到另一个集合。

1 object arrayTest extends App{
 2   var increase=(x:Int)=>x+1
 3   val someNumbers = List ( -11, -10, - 5, 0, 5, 10)
 4   var b = someNumbers.foreach(increase)
 5   println(b.getClass)
 6   var c = someNumbers.map(increase)
 7   println(c.getClass)
 8 
 9   c.foreach((x:Int)=>print(x+" "))
10   println()
11   c.map((x:Int)=>print(x+" "))
12 
13 }



      val list = List(1,2,3,4,5,100,102,105,109)
      list.foreach((x:Int)=>print(x+" "))
      println("")
      list.foreach((a:Int)=>print(a +" "))
      println("")
//      //省略参数的类型声明,Scala是可以进行类型推断的
      list.foreach(a => print(a + " "))
      println("")
//      //省略了参数也能玩得转
      list.foreach(print)

5、filter

package cn.bigdata.scala

object ArrayYieldDemo {
  def main(args: Array[String]) {
    //定义一个数组
    val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
    //将偶数取出乘以10后再生成一个新的数组
    val res = for (e <- arr if e % 2 == 0) yield e * 10
    println(res.toBuffer)

    //更高级的写法,用着更爽
    //filter是过滤,接收一个返回值为boolean的函数
    //map相当于将数组中的每一个元素取出来,应用传进去的函数
    val r = arr.filter(_ % 2 == 0).map(_ * 10)
    println(r.toBuffer)

  }
}

6、reduceLeft、reduceRight、foldLeft、foldRight、reduce

object TestDemo4 {
  def main(args: Array[String]): Unit = {
    val a = List(1,7,2,9)
    val a1 = a.reduceLeft(_ - _)//      ((1-7) - 2) - 9 = -17
    println(a1)
    val a2 = a.foldLeft(0)(_ - _) //    0-1-7-2-9 = -19
    println(a2)
    val a3 = a.reduceRight(_ - _)//      1-(7-(2-9)) = -13
    println(a3)
    val a4 = a.foldRight(0)(_ - _)//    1-(7-(2-(9-0))) = -13
    println(a4)
    val a5 = a.reduceRight(_ min _)//      最小
    println(a5)
    val a6 = a.reduceRight(_ max _)//      最大
    println(a6)
var list = List(1,2,3,4)      
var jian =  list.reduce(_ - _)//  1-2-3-4
    println(jian)   
var sum =  list.reduce(_ + _)//  1+2+3+4
    println(sum)
var sum =  list1.fold(5)(_ + _)// 5+1+2+3+4
    println(sum)
var sum =  list1.fold(5)((x,y)=>x+y)// 5+1+2+3+4
    println(sum)

    val a10 = (10/:lst1)(_-_) //foldLeft的另一种写法
    println("a10 = "+a10)

    val a11 = (lst1:\10)(_-_) //foldRight的另一种写法

    println("a11 = "+a11)
  }
}

感谢观看,scala一共五篇,只是入门,要学好,还是远远不够的,但是使用spark足够了,下篇会更新其他大数据文章,谢谢