Scala语言学习

scala语法

函数式编程

面向对象

集合类型

计算函数

* 调用方法时"."可以省略

 

scala语法

1、常量与变量

val:修饰常量 var:修饰变量

    //以下滑行开头
    val _abc="abc"

    //已操作符开头,且只能包括操作符
    val +-*/%^ = "hello"

    //可以使用反引号将保留字作为变量名称
    val `if`="if"
    println(`if`)

 

2、数据类型

image

 

    //空值 Unit
    def m1: Unit = {
      println("m1被调用")
    }

    val m: Unit = m1
    println(m)

    //空引用 Null,只能给引用类型复制
    //    val num:Int=null  错误的
    var stu: Stu = null
    println(stu)
    var str: String = null
    println(str)

    //Nothing
    def m2(num: Int): Int = {
      if (num == 0) {
        throw new NullPointerException
      } else {
        num + 1
      }
    }

    def m3(num: Int): Nothing = {
      throw new NullPointerException
    }

    val m22 = m2(2)
    println(m22)

 

3、数据转换

 

4、运算符

 

 5、流程控制

 (1)简单的控制

//if语句可以带有返回值
    println("------if语句可以带有返回值-----")
    var var1 = if (1 > 3) {
      println("123")
      "123"
    } else {
      println("123")
      "456"
    }
    println(var1)

    //类似三元运算符
    println("------类似三元运算符-----")
    var var2 = if (1 > 3) "123" else if (1 < 5) "456" else "789"
    println(var2)

 (2)for循环控制

    //循环推导式
    println("------循环推导式-----")
    for (i <- 1 to 3) {
      println(i)
    }
    for (i <- 1 until 3) {
      println(i)
    }
    for (i <- Range(1, 4)) {
      println(i)
    }
    for (i <- Array(1, 4)) {
      println(i)
    }

    //循环保卫
    println("------循环保卫-----")
    for (i <- 1 to 3 if i % 2 != 0) {
      println(i)
    }

    //循环步长
    println("------循环步长-----")
    for (i <- 1 to 10 by 2 if i % 3 != 0) {
      println(i)
    }

    for (i <- 1 to 10 by -2) {
      println(i) //无法到达时改语句不执行
    }
    //嵌套循环(双重for循环
    println("------嵌套循环-----")
    for (i <- 1 to 3; j <- 2 to 3) {
      println(i + " " + j)
    }
    //引入变量
    println("------引入变量-----")
    for (i <- 1 to 3; j = i * 2) {
      println(i + " " + j)
    }
    for //变形
    {i <- 1 to 3
     j = i * 2} {
      println(i + " " + j)
    }

    //循环返回值 使用yield关键字,指定for返回值,与多线程无关
    println("------循环返回值-----")
    val forRe: immutable.IndexedSeq[Int] = for (i <- 1 to 3) yield i
    println(forRe)

    //循环中断 scala中删除了break和continue
    println("------循环中断-----")
    try {
      for (i <- 1 to 3 ) {
        if(i==2){
          throw new Exception
        }
        println(i)
      }
    }catch {
      case e:Exception=>
    }
    //使用breaks类中断
    Breaks.breakable(
      for (i <- 1 to 3 ) {
        if(i==2){
          Breaks.break()
        }
        println(i)
      }
    )
    //再简化
    breakable(
      for (i <- 1 to 3 ) {
        if(i==2){
          break
        }
        println(i)
      }
    )
    println("抛出异常中断for")

 

 

 

 

函数式编程

 1、函数定义 

  //可变参数
    println("-----可变参数-----")
    def f1(str:String*):Unit={
      println(str)
    }
    f1("str1","str2")

    //参数的默认值
    println("-----参数的默认值-----")
    def f2(str:String="wgy"):Unit={
      println(str)
    }
    f2()
    f2("str1")

    //带命参数,赋值可指定名称赋值
    println("-----带命参数-----")
    def f3(str:String="str",age :Int):Unit={
      println(s"name${str} age${age}")
    }
    f3(age = 18,str = "wgy")
    f3(age = 25)

  

2、匿名函数 

    /*
    函数省略
     */
    println("函数省略")
    //定义一个匿名函数
    val myFun: String => Unit = (name: String) => {
      println(name)
    }

    //定义一个入参为函数的函数
    def func(thisFun: String => Unit): Unit = {
      thisFun("wgy scala")
    }
    //将匿名函数传入自定义函数中
    func(myFun)

    //1、定义的匿名函数入参类型可以省略
    //2、当只有一个入参时,入参的括号以省略
    //3、匿名函数只有一行,大括号可以省略
    func(name => println(name))

    //1、当参数只出现一次,入参可以省略后边参数用_代替
    //2、能推断出是一个函数题的话可以直接省略(_)如:func(println)
    func(println(_))

    //如果可以推断出,出入的是函数体,不是调用语句,下划线也可以省略
    func(println)


    /*
    函数作为值返回
     */
    println("函数作为值返回")
    def f(a: Int): Int = {
      a + 123
    }
    //函数作为值传递
    val f2: Int => Int = f //指定f2的类型后既可以把f当做整体传值
    val f1 = f _ //如果省略f1的类型时需要加一个空格下划线表示整体,如果没有下划线表示调用该函数了

  

3、闭包柯里化

闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和它所处的环境,称为闭包。

函数柯里化:把一个参数列表的多个参数,变成多个参数列表 

    /*
    柯里化
     */
    def f1(num1: Int): Int => Int = {
      def f2(num2: Int): Int = {
        num1 + num2
      }

      f2 _
    }

    val intToInt1: Int => Int = f1(456)
    println(intToInt1(678))
    println(f1(456)(789))

    //可以简化为
    def f2(num1: Int)(num2: Int): Int = {
      num1 + num2
    }

    val intToInt2: Int => Int = f2(12)
    println(intToInt2(678))
    println(f2(456)(789))

  

3、递归函数

    //递归函数
    println("-----递归函数-------")

    def factorial(n: Int): BigInt = {
      if (n <= 0) 1
      else n * factorial(n - 1)
    }

    println(factorial(5))

    /*尾递归
    为优化栈溢出问题,使用尾递归
    即自身的最后一行函数直接返回调用自身,不做其他操作
    */
    println("-----尾递归-------")

    def factorialTailrec(n: BigInt, acc: BigInt = 1): BigInt = {
      if (n <= 1) acc
      else factorialTailrec(n - 1, acc * n)
    }

    println(factorialTailrec(5))

  

 4、控制抽象

    /**
     * 控制抽象
     */
    //传值参数,常用形式
    println("------传值参数------")
    def f0(a:Int):Unit={
      println(a)
      println(a)
    }
    def f1():Int={
      println("函数f1被调用")
      12
    }

    f0(f1)

    /*
    传名参数
    将整个代码块传入,函数中该参数使用了几次,代码块就会被调用几次
     */
    println("------传名参数------")
    def f2(a: =>Int):Unit={
      println(a)
      println(a)
    }
    def f3(a:Int):Int={
      println("函数f2被调用")
      a
    }
    f2(f3(13))

  

5、使用柯里化实现while

    //方式1:使用普通方式实现
    def myWhile1(isdo: => Boolean): (=> Unit) => Unit = {
      def doLoop(op: => Unit): Unit = {
        if (isdo) {
          op
          myWhile1(isdo)(op)
        }
      }

      doLoop _
    }
    //方式2:使用匿名函数实现
    def myWhile2(isdo: => Boolean): (=> Unit) => Unit = {
      val myf=(op: =>Unit) => {
        if (isdo) {
          op
          myWhile2(isdo)(op)
        }
      }
      myf
    }
    //方式3:使用柯里化方式实现
    def myWhile3(isdo: => Boolean)(op: => Unit): Unit = {
      if (isdo) {
        op
        myWhile3(isdo)(op)
      }
    }
    
    //测试
    var n = 5
    myWhile2(n > 0) {
      println(n)
      n -= 1
    }

 

 6、懒加载关键字lazy

    val sum = (a: Int, b: Int) => {
      println("开始结算")
      a + b
    }
    lazy val num = sum(1, 2)
    println("开始输出结果")
    println("输出结果1" + num)
    println("输出结果2" + num)

 

 面相对象

 

1、包对象(package Object)

在scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以直接被访问

一个包下可以生成一个,只有当前包下的类可以使用,子包也不可用

package com

package object wgy {

  def commMethod(): Unit = {
    println("wgy 学习sacls")
  }

  var mess: String = "13213213"
}

 

 

2、类和对象

import scala.beans.BeanProperty

class Stu() {
  /*
  1、@BeanProperty:声明处get、set
  2、如果要给参数空值时使用下划线
   */
  private var name:String="wgy"

  @BeanProperty
  var age:Int=18

  @BeanProperty
  var sex:Boolean=_
}

object Stu {
  def main(args: Array[String]) = {
    val stu: Stu = new Stu
    println(stu.name)
    println(stu.age)
    println(stu.sex)
  }
}

  

2、构造器

import scala.beans.BeanProperty

//主构造器
class Student {
  @BeanProperty
  var name: String = _
  @BeanProperty
  var age: Int = _

  println("Student类主构造器被调用")

  //辅助构造器,需要直接或者间接调用主构造器,且必须放在构造器的第一行,可多个
  def this(name: String) {
    this()
    this.name = name
  }

  def this(name: String, age: Int) {
    this(name)
    this.age = age
  }

  def mothed() = {
    println("执行Student类中方法")
  }
}

/*
使用var指定为带参数的主构造器
带有var类似定义一个属性
不带传入仅仅是一个局部变量
 */
class Student2(var name: String, var age: Int)
class Student3(name: String, age: Int)


class Student4() extends Student {
  //重写方法是需要增加override
  override def mothed() = {
    println(s"执行Student3类中方法${name},${age}")
  }
}


object Student {
  def main(args: Array[String]): Unit = {
    val student4: Student4 = new Student4
    student4.mothed()
  }
}

 

3、继承

/**
 * 测试,输出结果
 * 1、父类主构造器函数本调用
   2、父类辅助构造器函数本调用
   3、子类主构造器函数本调用
   4、子类辅助构造器函数本调用
   父类展示name:wgy,age:18
   子类展示name:wgy,age:18,id:100001
 *
 */
object Per {
  def main(args: Array[String]): Unit = {
    val stu: Stu = new Stu("wgy", 18, "100001")
    stu.show
  }
}

/**
 * 父类
 */
class Per {
  var name: String = _
  var age: Int = _
  println("1、父类主构造器函数本调用")

  def this(name: String, age: Int) {
    this()
    println("2、父类辅助构造器函数本调用")
    this.name = name
    this.age = age
  }

  def show: Unit = {
    println(s"父类展示name:${this.name},age:${this.age}")
  }
}


/**
 * 子类
 * 子类继承父类, 此时父类可以传入参数
 * 在调用子类主构造器之前会先调用父类构造起器
 */
class Stu(name: String, age: Int) extends Per(name, age) {

  var id: String = _
  println("3、子类主构造器函数本调用")

  def this(_name: String, _age: Int, _id: String) {
    this(_name, _age)
    println("4、子类辅助构造器函数本调用")
    this.id = _id
  }

  override def show: Unit = {
    super.show
    println(s"子类展示name:${this.name},age:${this.age},id:${id}")
  }
}

 

 

4、多态(与java一致)

 

5、抽象类

 

 


集合类型

三大集合:序列Seq、集Set、映射Map

对于集合类,scala提供了可并与不可变的版本

不可变集合:scala.collection.immutable

可变集合:scala.collection.mutable


1、数组

不可变数组(不可变指的长度不可变,其位置上的值是可以赋值的)

//创建不可变数组

val array1: Array[Int] = new Array[Int](5)

//使用伴生对象创建对象

val array2: Array[Int] = Array(4, 5, 6, 7)

//数组赋值

array2(2) = 1000

//访问数组

println(array2.apply(2))

//遍历数组

for (i <- array2.indices) println(array2(i)) //根据下标循环

for (elem <- array2) println(elem) //增强for循环

array2.foreach(println)

val iterator: Iterator[Int] = array2.iterator //遍历器循环

while (iterator.hasNext)

println(iterator.next())

//连接素连接转为String输出

println(array2.mkString("--"))

//添加元素(创建新的数组返回)

array2.:+(789) //往末尾追加数据

array2 :+ 789 //功能同上,放大调用时可以将.用空格代替或者省略;参数只有一个时可以将括号省略

array2.+:(456) //往数组前追加数据

456 +: array2 //功能同上,当方法名称以:结尾时,此时方法左边为参数右边为对象(:在对象测)

//创建多维数组

val array3: Array[Array[Int]] = Array.ofDim(2, 2)


可变数组

val buffer: ArrayBuffer[Int] = new ArrayBuffer

val buffer2: ArrayBuffer[Int] = ArrayBuffer(12, 45, 78, 1998)

//访问元素

println(buffer2(0))

//添加元素

buffer2 :+ 999

999 +: buffer2 //以上两种方法不会在本数组添加,需要在返回的新数组中操作

buffer2 += 999 //在数组前追加元素,返回原数组(操作符不推荐在可变数组中使用)

888 +=: buffer2 //由于scala只会对结尾为:的方法处理为参数在前对象在后,所以要想在数组前追加元素,需要加:

buffer2.append(1, 2, 3, 4) //在数组前追加(推荐使用方法调用)

buffer2.prepend(9, 8, 7, 6) //在数组后添加

buffer2.insert(1, 1998) //在指定位置添加元素

buffer2.insertAll(1, buffer) //在指定位置添加数组

//删除元素

buffer2.remove(buffer2.size - 1) //在指定下标后删除一个元素

buffer2.remove(buffer2.size - 1, 1) //在指定下标后删除n个元素

buffer2 -= 1998//按值删除,删除首次出现的第一个该元素

//可变数组互转为不可变数组

val array: Array[Int] = buffer2.toArray

val buffer3: mutable.Buffer[Int] = array.toBuffer



2、List列表

不可变列表(不可变指的内容,长度均不可变)

//创建列表

val list1: List[Int] = List(1, 2, 3, 4, 5) //使用伴生对象的apply生成对象

val list2: List[Int] = Nil.::(789) //使用Nil的::方法生成对象

val list3: List[Int] = 789 :: Nil //由于::方法以:结尾,固可以省略后使用参数在前对象在后方是调用

val list4: List[Int] = 789 :: 456 :: 123 :: 147 :: Nil //结合多个从后向前创建得到

//添加元素(与数组类似)

val listNew: List[Int] = 465 +: list1 :+ 798

//合并列表

val list5: List[Any] = list3 :: list4//不会合并两list,是将list3作为元素添加到list4头

val list6: List[Any] = list3 ::: list4//合并两List

val list7: List[Any] = list3 ++ list4//功能同上,合并两List


可变列表

//创建可变列表

val list1: Any = new ListBuffer[Int]()

val list2: ListBuffer[Int] = ListBuffer(123, 456, 798)

val list3: ListBuffer[Int] = ListBuffer(777, 888, 999)

//合并可变List

val list4: ListBuffer[Int] = list2 ++ list3 //将两个List合并后返回新的list

list2 ++= list3 //将list3追加到list2队尾,并返回list2

list3 ++=: list2//追加到list2队首

//操作队列

list2.append(555)

list2.remove(1,2)

list2.update(1,10)

list2-=15//根据值删除元素


3、Set集合

不可变Set

//创建不可变Set

val set1: Set[Int] = Set(1, 2, 3, 4, 4, 5, 6, 7)

//添加元素

val set2: Set[Int] = set1.+(789)

val set3: Set[Int] = set1 + 456

//合并set

val set4: Set[Int] = set2 ++ set3

//删除元素

val set5: Set[Int] = set4 - 789

可变Set

//创建可变Set

val set1: mutable.Set[Int] = mutable.Set(1, 2, 3, 4, 4, 5, 7)

//添加元素

val set2: mutable.Set[Int] = set1 + 100 //原set不变,返回新的set

set1 += 555 //在set1中添加元素

set1.add(666) //同上

//删除元素

set1 -= 555

set1.remove(666)

//合并set

val set3: mutable.Set[Int] = set1 ++ set2


4、Map集合

不可变Map

//创建不可变Map

val map1: Map[String, Int] = Map("wgy" -> 10, "wll" -> 20, "whh" -> 18)

//访问元素

val maybeInt: Option[Int] = map1.get("wgy")

val value: Int = maybeInt.get//调用get方法获取对应值(None.get报错,Some.get返回值)

val value2: Int = map1.getOrElse("wgy",18)//直接获取值

val value3: Int = map1("www")//当值不存在报错

map1.keys.foreach(println)//遍历

可变Map

//创建可变Map

val map1: mutable.Map[String, Int] = mutable.Map("wgy" -> 10, "wll" -> 20, "whh" -> 18)

//添加元素

map1.put("wnb",100)

map1+=(("wnb",200))

map1.update("wnb", 300)

val map2: mutable.Map[String, Int] = map1.updated("wnb", 666)//区别update,该方法返回新对象

map2.remove("wgy")

//合并map

map1++=map2

 

5、元组

val tuple: (Int, String, Char, Boolean) = (1, "1", 'a', true)

tuple.productIterator.foreach(println)



6、可变队列

val queue: mutable.Queue[Int] = new mutable.Queue[Int]()

queue.enqueue(1,2,3,4,5,6,111)

val va: Int = queue.dequeue().

 

 

 

 

 

计算函数

1、转换类函数

val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
//过滤
val re: List[Int] = list.filter(_ % 2 == 0)

//map
val re2: List[Int] = list.map(_ * 2)

//扁平化
val list1: List[List[Int]] = List(List(1), List(11, 12), List(21, 22, 23), List(31, 42, 43, 44))
val flatten: List[Int] = list1.flatten

//扁平映射(结合map与flatten)
val re3: List[Int] = list1.flatMap(list => {
list :+ 999 //对数据中的元素添加一个数字再扁平化
})

//分组
val re5: Map[Int, List[List[Int]]] = list1.groupBy(_.size)
val re6: Map[Int, List[Int]] = list.groupBy(_ % 2)

 

2、规约类函数

    val re7: Int = list.reduce(_ + _) //reduce聚合操作
    val re8: Int = list.fold(100)(_ + _) //类似reduce,第一个参数给定初始值
    val map1: Map[String, Int] = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4)
    val map2: Map[String, Int] = Map("a" -> 10, "b" -> 20, "cc" -> 30, "dd" -> 40)
    val map: Map[String, Int] = map1 ++ map2
    println(map == map1)
    val stringList: List[String] = List("wgy", "wgy 123", "wgy 465 798", "wll wgy", "wll 123")
    val list2: List[String] = stringList.flatMap(_.split(" "))
    val map3: Map[String, List[String]] = list2.groupBy(w => w)
    val map4: Map[String, Int] = map3.map(kv => (kv._1, kv._2.size))
    val tuples: List[(String, Int)] = map4.toList.sortWith((a, b) => a._2 > b._2).take(3)
    println(tuples)

 

 

3、并行执行

val strings: immutable.IndexedSeq[String] = (1 to 5).map(x => Thread.currentThread().getName)
val strings1: ParSeq[String] = (1 to 5).par.map(x => Thread.currentThread().getName)
println(strings1)

 

3、模式匹配

    val x: Int = 5
    val y: Int = x match {
      case 0 =>
        println("798")
        798
      case 1 =>
        println("458")
        458
      case _ =>
        println("111")
        111
    }

    //模式守卫(可以对范围做匹配,我没明白if else不好使吗)
    val z: Int = x match {
      case i if i > 0 =>
        println("798")
        798
      case i if i == 0 =>
        println("458")
        458
      case _ =>
        println("111")
        111
    }

    //匹配常量

    def match1(x: Any): Unit = x match {
      case 1     => println("Int 1")
      case "wgy" => println("String wgy")
      case true  => println("boolean true")
      case '+'   => println("")
    }

    //匹配类型
    def match2(x: Any): Unit = x match {
      case i: Int    => println("798")
      case s: String => println("458666")
      case list: List[String] =>
        println("458777") //注意List的泛型匹配时存在泛型擦除,导致泛型被忽略所有List的类型都会匹配
      case list: Array[String] => println("458888") //注意Array不存在泛型擦除
      case a                   => println("111")
    }
    //匹配数组、列表(List)、元祖同理(自上而下匹配,当匹配到后边将不再匹配)
    for (elem <- List(Array(1, 0, 1), Array(1, 1), Array(0, 1), Array(0))) {
      elem match {
        case Array(0, _)    => println("(0,_)") //必须有两个元素,且第一个元素为0
        case Array(0, _*)   => println("(0,...)") //匹配开头0,后边有多个或者没有元素的数组类型
        case Array(1, 1)    => println("(1,1)")
        case Array(x, y)    => println("(x,y)")
        case Array(x, 0, z) => println("(x,0,z)")
        case _              => println("_")
      }
    }
    //元组
    val (xx, yy) = (1, "wgy") //相当于x=1,y="wgy"
    val List(first, second, _*) = List(2, "wll", 465, 798) //first=2,second=wll
    val fir :: sec :: rest =
      List(1, 2, 3, 4, 5) //区别上边fir=1 ,sec=2 ,rest=List(3,4,5)
    val list: List[(String, Int)] =
      List(("a", 1), ("b", 2), ("c", 3), ("d", 4), ("e", 1666))
    for ((v1, v2) <- list) println(v1 + ":" + v2)
    for (("a", v) <- list) println(v) //相当于过滤了第一个元素为”a“的

 

posted @ 2026-01-26 19:52  王啦啦  阅读(5)  评论(0)    收藏  举报