scala学习---3

1.map集合

// 创建一个不可变的Map
val ages = Map("Leo" -> 30, "Jen" -> 25, "Jack" -> 23)
ages("Leo") = 31
// 创建一个可变的Map
val ages = scala.collection.mutable.Map("Leo" -> 30, "Jen" -> 25, "Jack" -> 23)
ages("Leo") = 31  //值可以改变
// 使用另外一种方式定义Map元素
val ages = Map(("Leo", 30), ("Jen", 25), ("Jack", 23))

// 获取指定key对应的value,如果key不存在,会报错
val leoAge = ages("Leo")
val leoAge = ages("leo")
// 使用contains函数检查key是否存在
val leoAge = if (ages.contains("leo")) ages("leo") else 0
// getOrElse函数
val leoAge = ages.getOrElse("leo", 0)

// 更新不可变的map     都是赋给新的一个Map
val ages2 = ages + ("Mike" -> 36, "Tom" -> 40)
// 移除不可变map的元素
val ages3 = ages - "Tom"

// 遍历map的entrySet
for ((key, value) <- ages) println(key + " " + value)
// 遍历map的key
for (key <- ages.keySet) println(key)
// 遍历map的value
for (value <- ages.values) println(value)
// 生成新map,反转key和value
for ((key, value) <- ages) yield (value, key)

// SortedMap可以自动对Map的key的排序
val ages = scala.collection.immutable.SortedMap("leo" -> 30, "alice" -> 15, "jen" -> 25)

// LinkedHashMap可以记住插入entry的顺序
val ages = new scala.collection.mutable.LinkedHashMap[String, Int]
ages("leo") = 30
ages("alice") = 15
ages("jen") = 25

// 简单Tuple
val t = ("leo", 30)
// 访问Tuple
t._1  //_1获取key,_2获取value

// zip操作
val names = Array("leo", "jack", "mike")
val ages = Array(30, 24, 26)
val nameAges = names.zip(ages)
for ((name, age) <- nameAges) println(name + ": " + age)

2.伴生对象

// 如果有一个class,还有一个与class同名的object,那么就称这个object是class的伴生对象,class是object的伴生类
// 伴生类和伴生对象必须存放在一个.scala文件之中
// 伴生类和伴生对象,最大的特点就在于,互相可以访问private field

object Person {
  private val eyeNum = 2
  def getEyeNum = eyeNum
}

class Person(val name: String, val age: Int) {
  def sayHello = println("Hi, " + name + ", I guess you are " + age + " years old!" + ", and usually you must have " + Person.eyeNum + " eyes.")
}

3.枚举

// Scala没有直接提供类似于Java中的Enum这样的枚举特性,如果要实现枚举,则需要用object继承Enumeration类,并且调用Value方法来初始化枚举值
object Season extends Enumeration {
  val SPRING, SUMMER, AUTUMN, WINTER = Value
}

// 还可以通过Value传入枚举值的id和name,通过id和toString可以获取; 还可以通过id和name来查找枚举值
object Season extends Enumeration {
  val SPRING = Value(0, "spring")
  val SUMMER = Value(1, "summer")
  val AUTUMN = Value(2, "autumn")
  val WINTER = Value(3, "winter")
}
Season(0)
Season.withName("spring")

// 使用枚举object.values可以遍历枚举值
for (ele <- Season.values) println(ele)

4.apply说明

class Foo(foo: String) {
}

object Foo {
    def apply(foo: String) : Foo = {
        new Foo(foo)
    }
}

定义了一个Foo类,并且在这个类中,有一个伴生对象Foo,里面定义了apply方法。有了这个apply方法以后,在调用这个Foo类的时候,用函数的方式来调用:

object Client {

    def main(args: Array[String]): Unit = {
        val foo = Foo("Hello")
    }
}

我们用Foo("Hello")的方式,就得到了一个Foo类型的对象,这一切就是apply方法的功劳。如果没有apply方法,我们将需要使用new关键字来得到Foo对象。

apply方法的最佳实践方式之一就是用来做工厂。比如在Scala的标准库中,许多集合类给我们提供了apply方法来创建集合。

apply方法有点类似于java中的构造函数,接受构造参数变成一个对象。那么unapply方法就刚好相反,他是接受一个对象,从对象中提取出相应的值。 
unapply方法主要用于模式匹配中。此处参考:https://blog.csdn.net/bitcarmanlee/article/details/76736252

5.override和super

// Scala中,如果子类要覆盖一个父类中的非抽象方法,则必须使用override关键字
// override关键字可以帮助我们尽早地发现代码里的错误,比如:override修饰的父类方法的方法名我们拼写错了;比如要覆盖的父类方法的参数我们写错了;等等
// 此外,在子类覆盖父类方法之后,如果我们在子类中就是要调用父类的被覆盖的方法呢?那就可以使用super关键字,显式地指定要调用父类的方法

class Person {
  private var name = "leo"
  def getName = name
}
class Student extends Person {
  private var score = "A"
  def getScore = score
  override def getName = "Hi, I'm " + super.getName
}

6.trait也是有构造机制

 

1.在Scala中,trait也是有构造代码的,也就是trait中的,不包含在任何方法中的代码。2.构造trait时会先构造父trait,如果多个trait继承同一个父trait,则父trait只会构造一次;3、所有trait构造完毕之后,子类的构造函数执行。4.trait是没有接收参数的构造函数的,这是trait与class的唯一区别。5.在Scala中,trait也可以继承自class,此时这个class就会成为所有继承该trait的类的父类

7.将函数赋值给变量

// Scala中的函数是一等公民,可以独立定义,独立存在,而且可以直接将函数作为值赋值给变量
// Scala的语法规定,将函数赋值给变量时,必须在函数后面加上空格和下划线

def sayHello(name: String) { println("Hello, " + name) }
val sayHelloFunc = sayHello _
sayHelloFunc("leo")

8.匿名函数

// Scala中,函数也可以不需要命名,此时函数被称为匿名函数。// 可以直接定义函数之后,将函数赋值给某个变量;也可以将直接定义的匿名函数传入其他函数之中
// Scala定义匿名函数的语法规则就是,(参数名: 参数类型) => 函数体
// 这种匿名函数的语法必须深刻理解和掌握,在spark的中有大量这样的语法

val sayHelloFunc = (name: String) => println("Hello, " + name)

9.高阶函数

// 接收其他函数作为参数的函数,也被称作高阶函数(higher-order function)
val sayHelloFunc = (name: String) => println("Hello, " + name)
def greeting(func: (String) => Unit, name: String) { func(name) }
greeting(sayHelloFunc, "leo")

Array(1, 2, 3, 4, 5).map((num: Int) => num * num)

// 高阶函数的另外一个功能是将函数作为返回值
def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name)
val greetingFunc = getGreetingFunc("hello")
greetingFunc("leo")

10.高阶函数类型推断

// 高阶函数可以自动推断出参数类型,而不需要写明类型;而且对于只有一个参数的函数,还可以省去其小括号;如果仅有的一个参数在右侧的函数体内只使用一次,则还可以将接收参数省略,并且将参数用_来替代
// 诸如3 * _的这种语法!spark源码中大量使用了这种语法!

def greeting(func: (String) => Unit, name: String) { func(name) }
greeting((name: String) => println("Hello, " + name), "leo")
greeting((name) => println("Hello, " + name), "leo")
greeting(name => println("Hello, " + name), "leo")

def triple(func: (Int) => Int) = { func(3) }
triple(3 * _)

//下面是常用高阶函数
// map: 对传入的每个元素都进行映射,返回一个处理后的元素 Array(1, 2, 3, 4, 5).map(2 * _) // foreach: 对传入的每个元素都进行处理,但是没有返回值 (1 to 9).map("*" * _).foreach(println _) // filter: 对传入的每个元素都进行条件判断,如果对元素返回true,则保留该元素,否则过滤掉该元素 (1 to 20).filter(_ % 2 == 0) // reduceLeft: 从左侧元素开始,进行reduce操作,即先对元素1和元素2进行处理,然后将结果与元素3处理,再将结果与元素4处理,依次类推,即为reduce;reduce操作重点// 下面这个操作就相当于1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 (1 to 9).reduceLeft( _ * _) // sortWith: 对元素进行两两相比,进行排序 Array(3, 2, 5, 4, 10, 1).sortWith(_ < _)

 

11.Currying函数

// Curring函数,指的是,将原来接收两个参数的一个函数,转换为两个函数,第一个函数接收原先的第一个参数,然后返回接收原先第二个参数的第二个函数。
// 在函数调用的过程中,就变为了两个函数连续调用的形式
// 在Spark的源码中,也有体现,所以对()()这种形式的Curring函数。

def sum(a: Int, b: Int) = a + b
sum(1, 1)

def sum2(a: Int) = (b: Int) => a + b
sum2(1)(1)

def sum3(a: Int)(b: Int) = a + b

 12.return

// Scala中,不需要使用return来返回函数的值,函数最后一行语句的值,就是函数的返回值。在Scala中,return用于在匿名函数中返回值给包含匿名函数的带名函数,并作为带名函数的返回值。
// 使用return的匿名函数,是必须给出返回类型的,否则无法通过编译

def greeting(name: String) = {
  def sayHello(name: String):String = {
    return "Hello, " + name
  }
  sayHello(name)
}

 

posted @ 2018-08-28 17:54  聚云  阅读(116)  评论(0编辑  收藏  举报