Scala 学习(2)

元组

映射是K/V对偶的集合,对偶是元组的最简单形式,元组可以装着多个不同类型的值。

创建元组

获取元组中的值

元组中下标默认从1开始

将对偶的集合转换成映射

拉链操作

zip命令可以将多个值绑定在一起

转换为映射关系显示

注意:如果两个数组的元素个数不一致,拉链操作后生成的数组的长度为较小的那个数组的元素个数

 

集合                        

Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质

在Scala中集合有可变(mutable)和不可变(immutable)两种类型,immutable类型的集合初始化后就不能改变了(注意与val修饰的变量进行区别)

序列Seq

不可变的序列 import scala.collection.immutable._

在Scala中列表要么为空(Nil表示空列表)要么是一个head元素加上一个tail列表。

9 :: List(5, 2)  :: 操作符是将给定的头和尾创建一个新的列表

注意::: 操作符是右结合的,如9 :: 5 :: 2 :: Nil相当于 9 :: (5 :: (2 :: Nil))

list常用的操作符:

+: (elem: A): List[A] 在列表的头部添加一个元素

:: (x: A): List[A]     在列表的头部添加一个元素

:+ (elem: A): List[A] 在列表的尾部添加一个元素

++[B](that: GenTraversableOnce[B]): List[B] 从列表的尾部添加 另外一个列表

::: (prefix: List[A]): List[A] 在列表的头部添加另外一个列表

object ImmutListDemo {

  def main(args: Array[String]) {
    //创建一个不可变的集合
    val lst1 = List(1,2,3)
    //将0插入到lst1的前面生成一个新的List
    val lst2 = 0 :: lst1
    //类似于调用::方法
    val lst3 = lst1.::(0)

    val lst4 = 0 +: lst1
    val lst5 = lst1.+:(0)
    //将一个元素添加到lst1的后面产生一个新的集合
    val lst6 = lst1 :+ 4

    val lst0 = List(4,5,6)
    //将2个list合并成一个新的List
    val lst7 = lst1 ++ lst0
    //将lst1插入到lst0前面生成一个新的集合
    val lst8 = lst1 ++: lst0

    //将lst0插入到lst1前面生成一个新的集合
    val lst9 = lst1.:::(lst0)

    println(lst9)
  }
}

1.创建一个不可变的集合

2.将0插入到lst1的前面生成一个新的List

//将0插入到lst1的前面生成一个新的List
    val lst2 = 0 :: lst1

//类似于调用::方法 val lst3 = lst1.::(0)

val lst4 = 0 +: lst1

val lst5 = lst1.+:(0)

//将一个元素添加到lst1的后面产生一个新的集合 val lst6 = lst1 :+ 3

可变的序列 import scala.collection.mutable._

import scala.collection.mutable.ListBuffer

object MutListDemo extends App{
  //构建一个可变列表,初始有3个元素1,2,3
  val lst0 = ListBuffer[Int](1,2,3)
  //创建一个空的可变列表
  val lst1 = new ListBuffer[Int]
  //向lst1中追加元素,注意:没有生成新的集合
  lst1 += 4
  lst1.append(5)

  //将lst1中的元素最近到lst0中, 注意:没有生成新的集合
  lst0 ++= lst1

  //将lst0和lst1合并成一个新的ListBuffer 注意:生成了一个集合
  val lst2= lst0 ++ lst1

  //将元素追加到lst0的后面生成一个新的集合
  val lst3 = lst0 :+ 5
}

1.创建一个可变列表

2.向lst1中追加元素,注意:没有生成新的集合

lst1

+=

append

3.将lst1中的元素添加至lst0中  注意没有生成新的集合

4.将lst0和lst1合并成一个新的ListBuffer   注意:生成了一个集合

5.将元素追加到lst0的后面生成一个新的集合

Set

不可变的Set

object ImmutSetDemo extends App{
  val set1 = new HashSet[Int]()
  //将元素和set1合并生成一个新的set,原有set不变
  val set2 = set1 + 4
  //set中元素不能重复
  val set3 = set1 ++ Set(5, 6, 7)
  val set0 = Set(1,3,4) ++ set1
  println(set0.getClass)
}

元素与set1合并生成一个新的set(set2),原有set(set1)不变

set中元素不能重复

两个集合合并产生新的集合---->  ++操作

可变的Set

object MutSetDemo extends App{
  //创建一个可变的HashSet
  val set1 = new mutable.HashSet[Int]()
  //向HashSet中添加元素
  set1 += 2
  //add等价于+=
  set1.add(4)
  set1 ++= Set(1,3,5)
  println(set1)
  //删除一个元素
  set1 -= 5
  set1.remove(2)
  println(set1)
}

1.创建一个可变的HashSet

2.向HashSet中添加元素      +=操作等价于.add

3.向一个集合中加入另一个集合  ++=操作   (Set中不能重复)

4.删除一个元素

-=等价于remove

Map

object MutMapDemo extends App{
  val map1 = new mutable.HashMap[String, Int]()
  //向map中添加数据
  map1("spark") = 1
  map1 += (("hadoop", 2))
  map1.put("storm", 3)
  println(map1)

  //从map中移除元素
  map1 -= "spark"
  map1.remove("hadoop")
  println(map1)
}

1.向Map中添加数据(三种方式皆可)

2.从Map中移除元素

-= 与 remove作用相同

 

类、对象、继承、特质

Scala的类与Java、C++的类比起来更简洁,学完之后你会更爱Scala!!!

类的定义

//在Scala中,类并不用声明为public。
//Scala源文件中可以包含多个类,所有这些类都具有公有可见性。
class Person {
  //用val修饰的变量是只读属性,有getter但没有setter
  //(相当与Java中用final修饰的变量)
  val name= "zhangsan"

  //用var修饰的变量既有getter又有setter (get和set方法)
  var age: Int = 18

  //类私有字段,在本类中使用(伴生对象中也可使用)
  private var id :String ="123456"

  //对象私有字段,访问权限更加严格的,Person类的方法只能访问到当前对象的字段
  //(只能在Person类中使用)
  private[this] val sex = "M"
  private[this] var addr :String=_
}

//这是包的访问权限,这个类在com包及其子包中可见
private [com] class Person {
}
//单例对象
object Student{
  def main(args: Array[String]): Unit = {
    var M = new Man("zhsnafan",12)
    print(M.id)
  }
}

构造器

注意:主构造器会执行类定义中的所有语句

/**
  *每个类都有主构造器,主构造器的参数直接放置类名后面,与类交织在一起
  */
class Student(val name: String, val age: Int){
  //主构造器会执行类定义中的所有语句
  println("执行主构造器")
  try {
    println("读取文件")
    throw new IOException("io exception")
  } catch {
    case e: NullPointerException => println("打印异常Exception : " + e)
    case e: IOException => println("打印异常Exception : " + e)
  } finally {
    println("执行finally部分")
  }

  private var gender = "male"

  //用this关键字定义辅助构造器
  //定义多个辅助构造器,当参数数量、参数类型一致时,构造器的参数类型的顺序不能一致
  def this(name: String, age: Int, gender: String){
    //每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始
    this(name, age)
    println("执行辅助构造器")
    this.gender = gender
  }

//辅助构造器2
  def this(name:String,Course:String,age:Int){
    this(name,age)
  }
}
 
/**
  *构造器参数可以不带val或var,如果不带val或var的参数至少被一个方法所使用,
  *那么它将会被提升为字段
  */
//在类名后面加private就变成了私有的
class Queen private(val name: String, prop: Array[String], private var age: Int = 18){
  
  println(prop.size)

  //prop被下面的方法使用后,prop就变成了不可变得对象私有字段,等同于private[this] val prop
  //如果没有被方法使用该参数将不被保存为字段,仅仅是一个可以被主构造器中的代码访问的普通参数
  def description = name + " is " + age + " years old with " + prop.toBuffer
}

object Queen{
  def main(args: Array[String]) {
    //私有的构造器,只有在其伴生对象中使用
    val q = new Queen("hatano", Array("蜡烛", "皮鞭"), 20)
    println(q.description())
  }
}

对象

单例对象

在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的

  1. 存放工具方法和常量

  1. 高效共享单个不可变的实例

  1. 单例模式

object SingletonDemo {
  def main(args: Array[String]) {
    //单例对象,不需要new,用【类名.方法】调用对象中的方法
    val session = SessionFactory.getSession()
    println(session)
  }
}

object SessionFactory{
  //该部分相当于java中的静态块
  var counts = 5
  val sessions = new ArrayBuffer[Session]()
  while(counts > 0){
    sessions += new Session
    counts -= 1
  }

  //在object中的方法相当于java中的静态方法
  def getSession(): Session ={
    sessions.remove(0)
  }
}

class Session{

}

伴生对象

在Scala的类中,与类名相同的对象叫做伴生对象,类和伴生对象之间可以相互访问私有的方法和属性

class Dog {
  val id = 1
  private var name = "zhiyou"

  //伴生对象无法访问此对象
  private[this] val sex:String="M"

  def printName(): Unit ={
    //在Dog类中可以访问伴生对象Dog的私有属性
    println(Dog.CONSTANT + name )
  }
}

/**
  * 伴生对象
  */
object Dog {

  //伴生对象中的私有属性
  private val CONSTANT = "汪汪汪 : "

  def main(args: Array[String]) {
    val p = new Dog
    //访问私有的字段name
    p.name = "123"
    p.printName()
  }
}

apply方法

通常我们会在类的伴生对象中定义apply方法,当遇到类名(参数1,...参数n)时apply方法会被调用

//示例1
object ApplyDemo {
  def main(args: Array[String]) {
    //调用了Array伴生对象的apply方法
    //def apply(x: Int, xs: Int*): Array[Int]
    //arr1中只有一个元素5
    val arr1 = Array(5)
    println(arr1.toBuffer)

    //new了一个长度为5的array,数组里面包含5个null
    var arr2 = new Array(5)
  }
}

//示例2
package com.zhiyoulxj.Scala
class Teacher {
  var name:String = _
  var id = 123
}
object Teacher{
  def apply: Teacher = new Teacher(){
    print(1)
  }
  def main(args: Array[String]): Unit = {
    var t = Teacher
    t.apply
//    使用new方法创建对象与调用apply方法作用相同
//    var t1 =new Teacher
  }
}

应用程序对象

Scala程序都必须从一个对象的main方法开始,可以通过扩展App特质,不写main方法。

object AppObjectDemo extends App{
  //不用写main方法
  println("I love you Scala")
}

继承

扩展类

在Scala中扩展类的方式和Java一样都是使用extends关键字

重写方法

在Scala中重写一个非抽象的方法必须使用override修饰符

类型检查和转换

Scala

Java

obj.isInstanceOf[C]

obj instanceof C

obj.asInstanceOf[C]

(C)obj

classOf[C]

C.class

超类的构造

object ClazzDemo {
  def main(args: Array[String]) {
    //val h = new Human
    //println(h.fight)
  }
}
//接口
trait Flyable{
  def fly(): Unit ={
    println("I can fly")
  }
  def fight(): String
}
//抽象类
abstract class Animal {
  def run(): Int
  val name: String
  def eat(): Unit ={
    print("吃饭")
  }
}

class Human extends Animal with Flyable{
  val name = "abc"
  //打印几次"ABC"?
  val t1,t2,(a, b, c) = {
    println("ABC")
    (1,2,3)
  }
  println(a)
  println(t1._1)
------接口
  //接口中的方法无论是否实现,子类调用都需要加上override
  override def fight(): String = {
    "fight with 棒子"
  }
  override def fly(): Unit = {
//    super.fly()
    print("我爱自由")
  }
------超类
  //在子类中重写超类的抽象方法(该抽象方法在超类中没有实现)时,
  //不需要使用override关键字,写了也可以
  def run(): Int = {
    1
  }
  //超类或接口中实现过的方法在子类中调用都需要加上override(重写)
  override def eat(): Unit = {
  //    super.eat()
    print("吃满汉全席")
  }
}

多实现

如果想多继承,先用extends继承一个抽象类,然后再用with关键字实现一个接口,extends既可以继承抽象类,也可以实现接口,如果想要多重实现,则继续 with 接口名

 

模式匹配和样例类

Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句、类型检查等。

并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配

匹配字符串

Match  case

object CaseDemo01 extends App{
  val arr = Array("YoshizawaAkiho", "YuiHatano", "AoiSola")
  val name = arr(Random.nextInt(arr.length))
  name match {
    case "YoshizawaAkiho" => println("吉泽老师...")
    case "YuiHatano" => println("波多老师...")
    case _ => println("真不知道你们在说什么...")
  }
}
-----------------------------------------------------
object MatchDemo1 extends App {
  val  arr = Array("鲁班","张飞","李世民","太上道祖")
  val name = arr(Random.nextInt(arr.length))
  print(name)
  name match {
    case "鲁班" => print("小短腿儿")
    case "张飞" => print("阉人")
    case "李世民" => print("唐太宗")
    case _  => print("太上斩情")
  }

匹配类型

Int  String  Double

package cn.zhiyou.cases
import scala.util.Random

object CaseDemo01 extends App{
  //val v = if(x >= 5) 1 else if(x < 2) 2.0 else "hello"
  val arr = Array("hello", 1, 2.0, CaseDemo)
  val v = arr(Random.nextInt(4))
  println(v)
  v match {
    case x: Int => println("Int " + x)
    case y: Double if(y >= 0) => println("Double "+ y)
    case z: String => println("String " + z)
    case _ => throw new Exception("not match exception")
  }
}

注意case y: Double if(y >= 0) => ...

模式匹配的时候还可以添加守卫条件。如不符合守卫条件,将掉入case _中

匹配数组、元组

object CaseDemo03 extends App{

  val arr = Array(1, 3, 5)
  arr match {
    case Array(1, x, y) => println(x + " " + y)
    case Array(0) => println("only 0")
    case Array(0, _*) => println("0 ...")
    case _ => println("something else")
  }

  val lst = List(3, -1)
  lst match {
    case 0 :: Nil => println("only 0")   //只有0一个元素
    case x :: y :: Nil => println(s"x: $x y: $y")   //有两个元素
    case 0 :: tail => println("0 ...")  //有三个及三个以上的元素(0开头)
    case _ => println("something else")
  }

  val tup = (2, 3, 7)
  tup match {
    case (1, x, y) => println(s"1, $x , $y")
    case (_, z, 5) => println(z)
    case  _ => println("else")
  }
}

注意:在Scala中列表要么为空(Nil表示空列表)要么是一个head元素加上一个tail列表。

9 :: List(5, 2)  :: 操作符是将给定的头和尾创建一个新的列表

注意::: 操作符是右结合的,如9 :: 5 :: 2 :: Nil相当于 9 :: (5 :: (2 :: Nil))

样例类

在Scala中样例类是一种特殊的类,可用于模式匹配。case class是多例的,后面要跟构造参数,

case object是单例的

case class SubmitTask(id: String, name: String)
case class HeartBeat(time: Long)
case object CheckTimeOutTask

object CaseDemo04 extends App{
  val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))

  arr(Random.nextInt(arr.length)) match {
    case SubmitTask(id, name) => {
      println(s"$id, $name")//前面需要加上s, $id直接取id的值
    }
    case HeartBeat(time) => {
      println(time)
    }
    case CheckTimeOutTask => {
      println("check")
    }
  }
}

Option类型

在Scala中Option类型样例类用来表示可能存在或也可能不存在的值(Option的子类有Some和None)。Some包装了某个值,None表示没有值9

object OptionDemo {
  def main(args: Array[String]) {
    val map = Map("a" -> 1, "b" -> 2)
    val v = map.get("b") match {
      case Some(i) => i
      case None => 0
    }
    println(v)
    //更好的方式
    val v1 = map.getOrElse("c", 0)
    println(v1)
  }
}

map.getOrElse()主要就是防范措施,如果有值,那就可以得到这个值,如果没有就会得到一个默认值,传入的参数是(key,default)这种形式,返回值是:如果有key那就get(key),如果没有,就返回default

偏函数

被包在花括号内没有match的一组case语句是一个偏函数,它是PartialFunction[A, B]的一个实例,A代表参数类型,B代表返回类型,常用作输入模式匹配

object PartialFuncDemo  {
  def func1: PartialFunction[String, Int] = {
    case "one" => 1
    case "two" => 2
    case _ => -1
  }
  def func2(num: String) : Int = num match {
    case "one" => 1
    case "two" => 2
    case _ => -1
  }
  def main(args: Array[String]) {
    println(func1("one"))
    println(func2("one"))
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值