Loading

2-Scala进阶

Scala入门

Hello Scala

package com.lotuslaw.chapter01

/**
 * object:关键字,声明一个单例对象(伴生对象)
 * */

object Hello {
  def main(args: Array[String]): Unit = {
    println("Hello Scala")
    System.out.println("Hello scala")
  }
}

object

package com.lotuslaw.chapter01

class Student(name: String, var age: Int) {
  def printInfo(): Unit = {
    println(name + " " + age + " " + Student.school)
  }
}

// 引入伴生对象
object Student{
  val school: String = "lotuslaw"

  def main(args: Array[String]): Unit = {
    val alice = new Student("alice", 18)
    alice.printInfo()
    val bob = new Student("bob", 20)
    bob.printInfo()
  }
}

变量和数据类型

注释

package com.lotuslaw.chapter02

/*
* 多行注释
* */
object Test01_Comment {
  /**
   * 文档注释
   * */
  def main(args: Array[String]): Unit = {
    // 单行注释
    println("hello")
  }
}

变量

package com.lotuslaw.chapter02

import com.lotuslaw.chapter01.Student

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-18 16:46
 * @description:
 */
object Test02_Variable {
  def main(args: Array[String]): Unit = {
    var a: Int = 10
    //    (1)声明变量时,类型可以省略,编译器自动推导,即类型推导
    var a1 = 10
    val b1 = 23
    //    (2)类型确定后,就不能修改,说明 Scala 是强数据类型语言。
    var a2 = 155 // a2类型维Int
    // a2 = "Hello",报错
    //    (3)变量声明时,必须要有初始值
    // var a2: Int 报错
    //    (4)在声明/定义一个变量时,可以使用 var 或者 val 来修饰,var 修饰的变量可改变,val 修饰的变量不可改
    a1 = 12
    // b1 = 25  报错

    var alice = new Student("alice", 20)
    alice = null
    val bob = new Student("bob", 20)
    bob.age = 23
    bob.printInfo()
  }
}

标识符

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-18 16:56
 * @description:
 */
object Test03_Identifier {
  def main(args: Array[String]): Unit = {
    //    (1)以字母或者下划线开头,后接字母、数字、下划线
    val hello: String = ""
    var _abc = 123
    //    (2)以操作符开头,且只包含操作符(+ - * / # !等)
    val -+*/ = ""
    println(-+*/)
    //    (3)用反引号`....`包括的任意字符串,即使是 Scala 关键字(39 个)也可以
    val `dsa20-**&*&` = 10
    println(`dsa20-**&*&`)
  }
}

字符串

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-18 17:01
 * @description:
 */
object Test04_String {
  def main(args: Array[String]): Unit = {
    //    (1)字符串,通过+号连接
    val name: String = "alice"
    val age: Int = 18
    //    (2)printf 用法:字符串,通过%传值。
    printf("name=%s, age=%d\n", name, age)
    //    (3)字符串模板(插值字符串):通过$获取变量值
    val s1 =
      s"""
        |select
        | name, age
        |from user
        |where name="$name" and age=${age+1}
        |""".stripMargin
    println(s1)
  }
}

输入

package com.lotuslaw.chapter02

import scala.io.StdIn

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-18 17:35
 * @description:
 */
object Test05_Input {
  def main(args: Array[String]): Unit = {
    //    StdIn.readLine()、StdIn.readShort()、StdIn.readDouble()
    // 输入姓名
    println("input name:")
    var name = StdIn.readLine()
    // 输入年龄
    println("input age")
    var age = StdIn.readShort()
    // 输入薪水
    println("input salary")
    var sal = StdIn.readDouble()
    println(name + " " + age + " " + sal)
  }
}

数据类型

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-18 17:39
 * @description:
 */
object Test06_DataCategory {
  def main(args: Array[String]): Unit = {
    //    1)Scala中一切数据都是对象,都是Any的子类。
    //    2)Scala中数据类型分为两大类:数值类型(AnyVal)、引用类型(AnyRef),不管是值类型还是引用类型都是对象。
    //    3)Scala数据类型仍然遵守,低精度的值类型向高精度值类型,自动转换(隐式转换)
    //    4)Scala中的StringOps是对Java中的String增强
    //    5)Unit:对应Java中的void,用于方法返回值的位置,表示方法没有返回值。Unit是 一个数据类型,只有一个对象就是()。Void不是数据类型,只是一个关键字
    //    6)Null是一个类型,只 有一个对 象就 是null。它是所有引用类型(AnyRef)的子类。
    //    7)Nothing,是所有数据类型的子类,主要用在一个函数没有明确返回值时使 用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数。
  }
}

整数类型

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-19 22:16
 * @description:
 */
object Test07_Integer {
  /*
  * (1)Scala 各整数类型有固定的表示范围和字段长度,不受具体操作的影响,以保证Scala 程序的可移植性。
  * (2)Scala 的整型,默认为 Int 型,声明 Long 型,须后加‘l’或‘L’
  * (3)Scala 程序中变量常声明为 Int 型,除非不足以表示大数,才使用 Long
  * */
  def main(args: Array[String]): Unit = {
    // 正确
    var n1: Byte = 127
    var n2: Byte = -128

    // 错误
    //    var n3: Byte = 128
    //    var n4: Byte = -129
    var n5 = 10
    println(n5)
    var n6 = 922337207687667668L
    println(n6)

    // 建议在开发中需要高精度小数时,请选择Double,默认是Double
    var n7 = 2.67678786875f
    var n8 = 2.87988675665798
    println(n7)
    println(n8)
  }
}

字符型

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-19 22:25
 * @description:
 */
object Test08_CharType {
  def main(args: Array[String]): Unit = {
    //    (1)字符常量是用单引号 ' ' 括起来的单个字符。
    var c1: Char = 'a'
    println(c1)
    // 注意:这里涉及自动类型提升,其实编译器可以自定判断是否超出范围
    // 不过idea提示报错
    var c2: Char = 'a' + 1
    println(c2)
    //    (2)\t :一个制表位,实现对齐的功能
    println("姓名\t年龄")
    //    (3)\n :换行符
    println("西门庆\n潘金莲")
    //    (4)\\ :表示\
    println("c:\\岛国\\avi")
    //    (5)\" :表示"
    println("同学们都说:\"大海哥最帅\"")
  }
}

布尔类型

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-19 22:32
 * @description:
 */
object Test09_BooleanType {
  def main(args: Array[String]): Unit = {
    //  (1)布尔类型也叫 Boolean 类型,Booolean 类型数据只允许取值 true 和 false
    //  (2)boolean 类型占 1 个字节
    var isResult: Boolean = false
    var isResult2: Boolean = true
  }
}

特殊类型

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-19 22:34
 * @description:
 */
object Test10_SpecialType {
  def main(args: Array[String]): Unit = {
    /*
    * (1)Unit 类型用来标识过程,也就是没有明确返回值的函数。
    * 由此可见,Unit 类似于 Java 里的 void。Unit 只有一个实例——( ),这个实例也没有实
    * 质意义
    */
    def sayOk: Unit = {
      // Unit表示没有返回值,即void
    }

    println(sayOk)
    // (2) null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)
    var cat = new Cat()
    cat = null // 正确
    //    var n1: Int = null  // 报错
    //    println(n1)
    // (3) Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,
    // 而且由于 Nothing 是其他任意类型的子类,他还能跟要求返回值的方法兼容
    def test(): Nothing = {
      throw new Exception()
    }
    test
  }
}

class Cat {

}

自动类型转换

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @version: V1.0
 * @package: com.lotuslaw.chapter02
 * @create: 2021-07-19 22:42
 * @description:
 */
class Test11_ValueTransfer {
  def main(args: Array[String]): Unit = {
    //    (1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。
    var n = 1 + 2.0
    println(n)
    //    (2)把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。
    var n2: Double = 1.0
    //    var n3 : Int = n2  // 报错
    //    (3)(byte,short)和 char 之间不会相互自动转换。
    var n4 : Byte = 1
    // var c1 : Char = n4  // 报错
    var n5 : Int = n4
    //    (4)byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型
    var n6 : Byte = 1
    var c2 : Char = 1
    var n7 : Int = n6 + c2
    var n9 : Short = 9
    var n8 : Int = n6 + n9
  }
}

强制类型转换

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @create: 2021-07-24-9:09 上午
 * @package: com.lotuslaw.chapter02
 * @description:
 */
object Test12_ForceTransfer {
  def main(args: Array[String]): Unit = {
    //(1)将数据由高精度转换为低精度,就需要使用到强制转换
    var n1 : Int = 2.5.toInt  // 存在精度损失
    //(2)强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
    var r1 : Int = 10 * 3.5.toInt + 6 * 1.5.toInt
    var r2 : Int = (10 * 3.5 + 6 * 1.5).toInt
    println("r1=" + r1 + "\n" + "r2=" + r2)
  }
}

字符串转换

package com.lotuslaw.chapter02

/**
 * @author: lotuslaw
 * @create: 2021-07-24-9:13 上午
 * @package: com.lotuslaw.chapter02
 * @description:
 */
object Test13_StringTransfer {
  def main(args: Array[String]): Unit = {
    //(1)基本类型转 String 类型(语法:将基本类型的值+"" 即可)
    var str1 : String = true + ""
    var str2 : String = 4.5 + ""
    var str3 : String = 100 + ""
    //(2)String 类型转基本数值类型(语法:调用相关 API)
    var s1 : String = "12"
    var n1 : Byte = s1.toByte
    var n2 : Short = s1.toShort
    var n3 : Int = s1.toInt
    var n4 : Long = s1.toLong
  }
}

运算符

算数运算符

package com.lotuslaw.chapter03

/**
 * @author: lotuslaw
 * @create: 2021-07-24-9:31 上午
 * @package: com.lotuslaw.chapter03
 * @description:
 */
object Test01_Arithmetic {
  def main(args: Array[String]): Unit = {
    // (1)对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。
    var r1: Int = 10 / 3
    println("r1=" + r1)
    var r2: Double = 10 / 3
    println("r2=" + r2)
    var r3: Double = 10.0 / 3
    println("r3=" + r3)
    println("r3=" + r3.formatted("%.2f"))  // 保留小数点2位,使用四舍五入
    // (2)对一个数取模 a%b,和 Java 的取模规则一样。
    var r4 = 10 % 3
    println("r4=" + r4)
  }
}

关系运算符

package com.lotuslaw.chapter03

/**
 * @author: lotuslaw
 * @create: 2021-07-24-9:37 上午
 * @package: com.lotuslaw.chapter03
 * @description:
 */
object Test02_Relation {
  def main(args: Array[String]): Unit = {
    var a: Int = 2
    var b: Int = 1
    println(a > b)
    println(a >= b)
    println(a <= b)
    println(a < b)
    println("a==b" + (a == b))
    println(a != b)
    /*
    * Java:==比较两个变量本身的值,即两个对象在内存中的首地址;
    * equals 比较字符串中所包含的内容是否相同。
    * Scala:==更加类似于 Java 中的 equals,参照 jd 工具
    * */
    val s1 = "abc"
    val s2 = new String("abc")
    println(s1 == s2)  // true
    println(s1.eq(s2))  // false
  }
}

逻辑运算符

package com.lotuslaw.chapter03

/**
 * @author: lotuslaw
 * @create: 2021-07-24-9:44 上午
 * @package: com.lotuslaw.chapter03
 * @description:
 */
object Test03_Logic {
  def main(args: Array[String]): Unit = {
    // && || !
    var a = true
    var b = false
    println("a&&b=" + (a && b))  // false
    println("a||b=" + (a || b))  // true
    println("!(a&&b)=" + (!(a && b)))  // true
  }
}

赋值运算符

package com.lotuslaw.chapter03

/**
 * @author: lotuslaw
 * @create: 2021-07-24-9:47 上午
 * @package: com.lotuslaw.chapter03
 * @description:
 */
object Test04_Assignment {
  def main(args: Array[String]): Unit = {
    /*
    * =
    * +=
    * -=
    * *=
    * /=
    * %=
    * <<= 左移后赋值
    * >>= 右移后赋值
    * &= 按位与后赋值
    * ^= 按位异或后赋值
    * |= 按位或后赋值
    * Scala中没有++ -- 操作符
    * */
  }
}

位运算符

package com.lotuslaw.chapter03

/**
 * @author: lotuslaw
 * @create: 2021-07-24-9:50 上午
 * @package: com.lotuslaw.chapter03
 * @description:
 */
object Test05_Position {
  def main(args: Array[String]): Unit = {
    val a: Int = 60
    val b: Int = 13
    println(a & b)  // 按位与
    println(a | b)  // 按位或
    println(a ^ b)  // 按位异或
    println(~ a)  // 按位取反
    println(a << 2)  // 左移运算
    println(a >> 2)  // 右移运算
    println(a >>> 2)  // 无符号右移
  }
}

所有运算符都是方法

package com.lotuslaw.chapter03

/**
 * @author: lotuslaw
 * @create: 2021-07-24-9:55 上午
 * @package: com.lotuslaw.chapter03
 * @description:
 */
object Test06_Opt {
  def main(args: Array[String]): Unit = {
    // 在 Scala 中其实是没有运算符的,所有运算符都是方法。
    val i: Int = 1.+(1)
    // (1)当调用对象的方法时,.可以省略
    val j: Int = 1 + (1)
    // (2)如果函数参数只有一个,或者没有参数,()可以省略
    val k:Int = 1 + 1
    println(1.toString())  // 1
    println(1 toString())  // 1
    println(1 toString)  // 1
  }
}

流程控制

选择

package com.lotuslaw.chapter04

import scala.io.StdIn

/**
 * @author: lotuslaw
 * @create: 2021-07-24-9:58 上午
 * @package: com.lotuslaw.chapter04
 * @description:
 */
object Test01_IfElse {
  def main(args: Array[String]): Unit = {
    println("input age:")
    var age = StdIn.readShort()
    // Scala中if else 表达式其实是有返回值的,具体返回值取决于满足条件的代码的最后一行内容
    // Scala中返回值类型不一致,取它们共同的祖先类型
    val res: Any = if (age < 18) {
      "童年"
    } else if (age < 30) {  // (age >= 18 && age < 30)
      "中年"
    } else {
      if (age < 60) {
        "中老年"
      } else {
        "老年"
      }
    }
    println(res)
    // java 中的三元运算符可以用if else 实现
    // JAVA res = flag ? 1 : 0
    println("请输入年龄:")
    val age2 = StdIn.readShort()
    val res2: Any = if (age < 18) "童年" else "成年"
    "不起作用"  // 无害亦无用
    println(res2)
  }
}

For循环

package com.lotuslaw.chapter04

/**
 * @author: lotuslaw
 * @create: 2021-07-24-10:21 上午
 * @package: com.lotuslaw.chapter04
 * @description:
 */
object Test02_For {
  def main(args: Array[String]): Unit = {
    // 左闭右闭
    for (i <- 1 to 5) {
      println("哈哈哈哈")
    }
    // 左闭右开
    for (j <- 1 until 5+1) {
      println("嘿嘿嘿嘿")
    }
    // 循环守卫
    for (i <- 1 to 3 if i != 2) {
      print(i + " ")
    }
    println()
    for (i <- 1 to 5 if i != 3) {
      println(i + "呵呵")
    }
    // 指定循环步长
    for (i <- 1 to 10 by 2) {
      println(i + "吼吼")
    }
    // 循环嵌套,需要加;隔断逻辑
    for (i <- 1 to 3; j <- 1 to 4) {
      println("i=" + i + " " + "j=" + j)
    }
    // 引入变量
    for (i <- 1 to 3; j = 4 - i) {  // 只循环i的循环次
      println("i=" + i + " " + "j=" + j)
    }
    // for推导式有一个不成文的约定:当for推导式包含多个表达式时,一般每行一个表达式,并用花括号代替圆括号
    for {
      i <- 1 to 3
      j = 4 - i
    } {
      println("i=" + i + " " + "j=" + j)
    }
    // 循环返回值,将遍历过程中处理的结果返回到一个新Vector集合中,使用yield关键字,开发中很少使用
    val res = for (i <- 1 to 10) yield i
    println(res)
    var res2 = for (i <- 1 to 10) yield {
      i * 2
    }
    println(res2)
    // 倒序
    for (i <- 1 to 10 reverse) {
      println(i)
    }
  }
}

While循环

package com.lotuslaw.chapter04

/**
 * @author: lotuslaw
 * @create: 2021-07-24-10:40 上午
 * @package: com.lotuslaw.chapter04
 * @description:
 */
object Test03_While {
  def main(args: Array[String]): Unit = {
    var i = 0
    while (i < 10) {
      println("哈哈" + i)
      i += 1
    }
    var j = 0
    do {
      println("嘿嘿" + j)
      j += 1
    } while (j < -1)
  }
}

循环退出

package com.lotuslaw.chapter04

import scala.util.control.Breaks

/**
 * @author: lotuslaw
 * @create: 2021-07-24-10:42 上午
 * @package: com.lotuslaw.chapter04
 * @description:
 */
object Test04_Break {
  def main(args: Array[String]): Unit = {
    /**
     * Scala内置控制结构特地地去掉了break和continue,是为了更好地适应函数式编程,推荐使用函数式的风格解决break和continue的功能,
     * 而不是一个关键字。Scala中使用breakable控制结构来实现break和continue功能
     * */
    // 采用异常方式退出循环
    try {
      for (elem <- 1 to 10) {
        println(elem)
        if (elem == 5) throw new RuntimeException
      }
    } catch {
      case e =>
    }
    println("正常结束循环")
    // 采用Scala自带的函数,退出循环
    Breaks.breakable(
      for (elem <- 1 to 10) {
        println(elem)
        if (elem == 5) Breaks.break()
      }
    )
    // 对break进行省略,import scala.util.control.Breaks._
    Breaks.breakable {
      for (elem <- 1 to 10) {
        println(elem)
        if (elem == 5) Breaks.break
      }
    }
    println("正常结束循环")
    for (elem <- 1 to 10) {
      if (elem % 2 == 1) {
        println(elem)
      } else {
        println("continue")
      }
    }
  }
}

九九乘法表

package com.lotuslaw.chapter04

/**
 * @author: lotuslaw
 * @create: 2021-07-24-10:55 上午
 * @package: com.lotuslaw.chapter04
 * @description:
 */
object Test05_NineNine {
  def main(args: Array[String]): Unit = {
    for (i <- 1 to 9; j <- 1 to i) {
      print(i + "*" + j + "=" + i * j + " ")
      if (j == i) println()
    }
  }
}

函数式编程

函数与方法

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-11:01 上午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test01_Function {
  // 方法可以进行重载和重写
  def main(): Unit = {

  }

  def main(args: Array[String]): Unit = {
    // 函数定义
    def f(arg: String): Unit = {
      println(arg)
    }
    // 函数调用
    f {
      "Hello World"
    }

    /**
     * 1、为完成某一功能的程序语句集合,称为函数。类中的函数称之为方法
     * 2、Scala语言可以在任何的语法结构中声明任何的语法,函数没有重载和重写的概念;方法可以进行重载和重写;Scala中函数可以嵌套定义
     * */
    // Scala语言可以在任何的语法结构中声明任何的语法
    import java.util.Date
    // 定义函数
    //    def test(): Unit = {
    //      println("无参,无返回值")
    //    }
    test("")
    // Scala中可以嵌套定义函数
    def test2(): Unit = {
      def test3(name: String): Unit = {
        println("函数可以嵌套定义")
      }
      test3("")
    }
    test2()
  }
  // 定义对象的方法
  def test(name: String): Unit = {
    println("hi")
  }
}

函数声明

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-11:18 上午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test02_FunctionDeclare {
  def main(args: Array[String]): Unit = {
    // 无参,无返回值
    def test1(): Unit = {
      println("无参,无返回值")
    }
    test1()
    // 无参,有返回值
    def test2(): String = {
      return "无参,有返回值"
    }
    println(test2())
    // 有参,无返回值
    def test3(s: String): Unit = {
      println(s)
    }
    test3("lotuslaw")
    // 有参,有返回值
    def test4(s: String): String = {
      return s + "有参,有返回值"
    }
    println(test4("lotuslaw"))
    // 多参,无返回值
    def test5(name: String, age: Int): Unit = {
      println(s"$name, $age")
    }
    test5("lotuslaw", 18)
  }
}

函数参数

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-11:27 上午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test03_FunctionParameter {
  def main(args: Array[String]): Unit = {
    // 可变参数
    def test(s: String*): Unit = {
      println(s)
    }
    // 有输入参数,输出Array
    test("Hello", "Scala")
    // 无输入参数,输出List
    test()
    // 如果参数列表中存在多个参数,那么可变参数一般放置在最后
    def test2(name: String, s: String*): Unit = {
      println(name + "," + s)
    }
    test2("Scala", "Java")
    // 参数默认值
    def test3(name: String, age: Int = 18): Unit = {
      println(s"$name, $age")
    }
    // 如果参数传递了值,那么会覆盖默认值
    test3("lotuslaw", 27)
    // 如果参数有默认值,在调用的时候,可以省略这个参数
    test("Scala")
    // 一般情况下,将有默认值的参数放置在参数列表的最后,因为scala中参数传递是从左到右
    // 带名参数
    test3(name = "lotuslaw")
  }
}

函数至简原则

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-11:35 上午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test04_FunctionSimplify {
  def main(args: Array[String]): Unit = {
    // 函数标准写法
    def f(s: String): String = {
      return s + " lotuslaw"
    }
    println(f("Hello"))
    // 至简原则:能省则省
    // return可以省略,Scala会使用函数体的最后一行代码作为返回值
    def f1(s: String): String = {
      s + " lotuslaw"
    }
    println(f1("Hello"))
    // 如果函数体只有一行代码,可以省略花括号
    def f2(s: String): String = s + " lotuslaw"
    println(f2("Hello"))
    // 返回值类型如果能够推断出来,那么可以省略
    def f3(s: String) = s + " lotuslaw"
    println(f3("Hello"))
    // 如果有return,则不能省略返回值类型,必须指定
    def f4(s: String): String = {
      return s + " lotuslaw"
    }
    println(f4("Hello"))
    // 如果函数明确声明Unit,那么函数体中使用return关键字,也不起作用
    def f5(): Unit = {
      return "lotuslaw"
    }
    println(f5())
    // Scala如果期望是无返回值类型,可以省略等号,将无返回值的函数称之为过程
    def f6() {
      "lotuslaw"
    }
    println(f6())
    // 如果函数无参,但是声明了参数列表,那么调用时,小括号可加可不加
    def f7() = "lotuslaw"
    println(f7)
    println(f7())
    // 如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
    def f8 = "lotuslaw"
    println(f8)
    // 如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
    println("==========")
    def f9 = (x: String) => {println("lotuslaw")}
    def f10(f: String => Unit) = {
      f("")
    }
    f10(f9)  // 调了f9,打印的是f9的结果
    println(f10((x: String) => {println("lotuslaw")}))  // 调了f9,f9打印,打印f10的Unit对象()
  }
}

函数高级

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-1:13 下午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test05_FunctionAdvanced {
  def main(args: Array[String]): Unit = {
    // 函数可以作为值进行传递
    // 调用foo函数,把返回值给变量f
    val f = foo
    println(f)
    // 在被调用函数foo后面加上_,相当于把函数foo当成一个整体,传递给变量f1
    val f1 = foo _
    foo()
    f1()
    // 如果明确变量类型,那么不使用下划线也可以将函数作为整体传递给变量
    println("========")
    var f2: () => Int = foo
    f2()
    // 函数可以作为参数进行传递
    // 定义一个函数,函数参数还是一个函数签名;f表示函数名称;(Int, Int)表示输入两个Int参数;Int表示函数返回值
    def f11(f: (Int, Int) => Int): Int = {
      f(2, 4)
    }
    // 定义一个函数,参数和返回值类型和f1的输入参数一致
    def add(a: Int, b: Int): Int = a + b
    // 将add函数作为参数传递给f11函数,如果能够推断出来不是调用,_可以省略
    println(f11(add))
    println(f11(add _))
    // 函数可以作为返回值返回
    def f111() = {
      def f222() = {

      }
      f222 _
    }
    val fff = f111()
    // 因为f111函数的返回值依然是函数,所以变量fff可以作为函数继续调用
    fff()
    // 上面的代码可以简化为
    f111()()
  }
  def foo(): Int = {
    println("foo...")
    1
  }
}

高级函数map、filter、reduce

package com.lotuslaw.chapter05

import scala.collection.mutable.ArrayBuffer

/**
 * @author: lotuslaw
 * @create: 2021-07-24-1:54 下午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test06_FunctionAdvancedMFR {
  def main(args: Array[String]): Unit = {
    // map映射
    def map(arr: Array[Int], op: Int => Int) = {
      for (elem <- arr) yield op(elem)
    }
    val arr = map(Array(1, 2, 3, 4), (x: Int) => {
      x * x
    })
    println(arr.mkString(","))
    // filter过滤,有参数,且参数在后面只使用一次,则参数省略且后面参数用_表示
    def filter(arr: Array[Int], op: Int => Boolean) = {
      var arr1: ArrayBuffer[Int] = ArrayBuffer[Int] ()  // 初始化
      for (elem <- arr if op(elem)) {
        arr1.append(elem)
      }
      arr1.toArray
    }
    var arr1 = filter(Array(1, 2, 3, 4), _ % 2 == 1)
    println(arr1.mkString(","))
    // reduce 聚合,有多个参数,且每个参数在后面只使用一次,则参数省略且后面参数用_表示,第n个_代表n个参数
    def reduce(arr: Array[Int], op: (Int, Int) => Int) = {
      var init: Int = arr(0)
      for (index <- 1 until arr.length) {
        init = op(init, arr(index))
      }
      init
    }
    val arr2 = reduce(Array(1, 2, 3, 4), _ * _)
    println(arr2)
  }
}

匿名函数

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-1:33 下午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test07_FunctionAnonymous {
  def main(args: Array[String]): Unit = {
    // 定义一个函数:参数包含数据和逻辑函数
    def operation(arr: Array[Int], op: Int => Int) = {
      for (elem <- arr) yield op(elem)
    }
    // 定义逻辑函数
    def op(ele: Int): Int = {
      ele + 1
    }
    // 标准函数调用
    val arr = operation(Array(1, 2, 3, 4), op)
    println(arr.mkString(","))
    // 采用匿名函数
    val arr1 = operation(Array(1, 2, 3, 4), (ele: Int) => {
      ele + 1
    })
    println(arr1.mkString(","))
    // 参数的类型可以省略,会根据形参进行自动的推导
    val arr2 = operation(Array(1, 2, 3, 4), (ele) => {
      ele + 1
    })
    println(arr2.mkString(","))
    // 类型省略之后,发现只有一个参数,则圆括号可以省略;其它情况:没有参数和参数超过1的永远不能省略圆括号
    val arr3 = operation(Array(1, 2, 3, 4), ele => {
      ele + 1
    })
    println(arr3.mkString(","))
    // 匿名函数只有一行,则大括号也可以省略
    val arr4 = operation(Array(1, 2, 3, 4), ele => ele + 1)
    println(arr4.mkString(","))
    // 如果参数只出现一次,则参数省略且后面参数可以用_代替
    val arr5 = operation(Array(1, 2, 3, 4), _ + 1)
    println(arr5.mkString(","))
    def calculator(a: Int, b: Int, op: (Int, Int) => Int): Int = {
      op(a, b)
    }
    // 标准版
    println(calculator(2, 3, (x: Int, y: Int) => {x + y}))
    // 如果只有一行,则大括号也可以省略
    println(calculator(2, 3, (x: Int, y: Int) => x + y))
    // 参数的类型也可以省略,会根据形参进行自动的推导
    println(calculator(2, 3, (x, y) => x + y))
    // 如果参数只出现一次,则参数省略且后面参数可以用_代替
    println(calculator(2, 3, _ + _))
  }
}

函数柯里化&闭包

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-2:19 下午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test08_FunctionCurrieClosure {
  def main(args: Array[String]): Unit = {
    /**
     * 1、闭包:如果有个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境称为闭包
     * 2、函数柯里化:把一个参数列表的多个参数,变成多个参数列表
     * */
    def f1() = {
      var a: Int = 10
      def f2(b: Int) = {
        a + b
      }
      f2 _
    }
    // 在调用时,f1函数执行完毕后,局部变量a应该随着栈空间释放掉
    val f = f1()
    // 但是在此处,变量a其实并没有释放,而是包含在了f2函数的内部,形成了闭合的效果
    println(f(3))
    println(f1()(3))
    // 函数柯里化,其实就是将复杂的函数逻辑变得简单化,函数柯里化一定存在闭包
    def f3(a: Int)(b: Int) = {
      a + b
    }
    println(f3(1)(4))
  }
}

递归

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-2:39 下午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test09_FunctionRecursion {
  def main(args: Array[String]): Unit = {
    /**
     * 递归算法
     * 1、方法调用自身
     * 2、方法必须要有跳出的逻辑
     * 3、方法调用自身时,传递的参数应该有规律
     * 4、Scala中的递归必须声明函数返回值类型
     * */
    println(test(5))
  }
  def test(i: Int): Int = {
    if (i == 1) {
      1
    } else {
      i * test(i - 1)
    }
  }
}

控制抽象

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-2:42 下午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test10_FunctionControl {
  def main(args: Array[String]): Unit = {
    // 值调用:把计算后的值传递过去
    // 通过匿名函数定义一个函数变量f
    def f = () => {
      println("f...")
      10
    }
    foo(f())
    // 名调用:把代码传递过去;JAVA只有值调用,Scala既有值调用又有名调用
    fooo(f())
    // 传递代码块
    foooo({
      println("aaa")
    })
    // 小括号可以省略
    foooo {
      println("aaa")
    }
    // 自定义while循环
    println("========")
    var i: Int = 1
    myWhile(i < 10) {  // {}传递代码块,({})小括号可以省略
      println(i)
      i += 1
    }
  }
  def foo(a: Int): Unit = {
    println(a)
    println(a)
  }
  def fooo(a: =>Int): Unit = {
    // =>Int 代码块的返回值是Int
    // 代码快传递给a,a出现一次,就把对应的代码块执行一次
    println(a)
    println(a)
  }
  def foooo(a: =>Unit): Unit = {
    println(a)
    println(a)
  }
  def myWhile(condition: =>Boolean) (op: =>Unit): Unit = {
    if (condition) {
      op
      myWhile(condition)(op)
    }
  }
}

惰性加载

package com.lotuslaw.chapter05

/**
 * @author: lotuslaw
 * @create: 2021-07-24-3:10 下午
 * @package: com.lotuslaw.chapter05
 * @description:
 */
object Test11_FunctionLazy {
  def main(args: Array[String]): Unit = {
    /**
     * 1、当函数返回值被声明为lazy时,函数的执行将被推迟,知道我们首次对此取值,该函数才会执行,这种函数我们称之为惰性函数
     * 2、注意,lazy 不能修饰var类型的变量
     * */
    lazy val res = sum(10, 30)
    println("--------")
    println("res=" + res)
  }
  def sum(n1: Int, n2: Int): Int = {
    println("sum 被执行。。。")
    n1 + n2
  }
}

面向对象

Scala包

/**
 * 1、基本语法 package 包名
 * 2、Scala包的三大作用,和JAVA一样:区分相同名字的类;当类很多时,可以很好的管理类;控制访问范围
 * 3、com.公司名.项目名.业务模块名
 * 4、Scala有两种包的管理风格,一种方式和Java的包管理风格相同,每个源文件一个包,包名用"."进行分割,表示层级关系,另一种嵌套风格如下:
 * 5、在Scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以被直接访问
 * 6、和Java一样,可以在顶部使用import导入包,在这个文件中的所有类都可以使用
 * 7、局部导入:什么时候使用,什么时候导入。在其作用范围内都可以使用
 * 8、通配符导入:import java.util._
 * 9、给类起名:import java.util.{ArrayList=>JL}
 * 10、导入相同包的多个类:import java.util.{HashSet, ArrayList}
 * 11、屏蔽类:import java.util.{ArrayList=>_,_}
 * 12、Scala中三个默认的导入分别是: import java.lang._    import scala._    import scala.Predef._
 */
// 报红是因为idea对scala支持度不够
package com {
  import com.lotuslaw.Inner  // 父包访问子包需要导包
  object Outer {
    val out: String = "out"
    def main(args: Array[String]): Unit = {
      println(Inner.in)
    }
  }
  package lotuslaw {
    object Inner {
      val in: String = "in"
      def main(args: Array[String]): Unit = {
        println(Outer.out)  // 子包访问父包无需导包
      }
    }
  }
}

package other {

}

默认public

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-3:53 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
// Scala语法中,类并不声明为public,所有这些类都具有公共可见性,即默认就是public
class Test02_ClassObject {

}

// 一个Scala源文件可以包含多个类
class Person {

}

Bean 属性(@BeanPropetry)自动生成规范的 setXxx/getXxx 方法

package com.lotuslaw.chapter06

import scala.beans.BeanProperty

/**
 * @author: lotuslaw
 * @create: 2021-07-24-4:05 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
// Bean 属性(@BeanPropetry),可以自动生成规范的 setXxx/getXxx 方法
class Test03_Person {
  var name: String = "bobo"
  var age: Int = _  // _表示给属性一个默认值
  @BeanProperty var sex: String = "男"
  // val修饰的属性不能赋默认值,必须显示指定
}

object Test03_Person {
  def main(args: Array[String]): Unit = {
    var person = new Test03_Person()
    println(person.name)
    person.setSex("女")
    println(person.getSex)
  }
}

访问权限

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-4:12 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
class Test04_Authority {
  /**
   * 在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,你可以通过类似的修饰符达到同样的效果。但是使用上有区别。
   * (1)Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字。
   * (2)private 为私有权限,只在类的内部和伴生对象中可用。
   * (3)protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以访问,同包无法访问。
   * (4)private[包名]增加包访问权限,包名下的其他类也可以使用
   */
}

class Person2 {
  private var name: String = "bobo"
  protected var age: Int = 18
  private[chapter06] var sex: String = "男"

  def say(): Unit = {
    println(name)
  }
}

object Person2 {
  def main(args: Array[String]): Unit = {
    // 在Scala中,括号是可选的,用于从具有无参数构造函数的类中创建对象
    val person = new Person2
    person.say()
    println(person.name)
    println(person.age)
  }
}

class Teacher extends Person2 {
  def test(): Unit = {
    this.age
    this.sex
  }
}

class Animal {
  def test: Unit = {
    new Person2().sex
  }
}

对象方法

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-4:22 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
class Test05_Method {

}

class Person3 {
  def sum(n1: Int, n2: Int): Int = {
    n1 + n2
  }
}

object Person3 {
  def main(args: Array[String]): Unit = {
    val person = new Person3()
    println(person.sum(10, 20))
  }
}

对象

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-4:27 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
class Test06_CreateObject {
  /**
   * (1)val 修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
   * (2)var 修饰对象,可以修改对象的引用和修改对象的属性值
   * (3)自动推导变量类型不能多态,所以多态需要显示声明
   */
}

class Person6 {
  var name: String = "lotuslaw"
}

object Person6 {
  def main(args: Array[String]): Unit = {
    val person = new Person6()
    person.name = "ok"
    println(person.name)
  }
}

构造器

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-4:36 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
class Test07_Constructor {
  /**
   * 和 Java 一样,Scala 构造对象也需要调用构造方法,并且可以有任意多个构造方法。Scala 类的构造器包括:主构造器和辅助构造器
   * (1)辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型来区分。
   * (2)辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。
   * (3)构造器调用其他另外的构造器,要求被调用构造器必须提前声明。
   * class 类名(形参列表) { // 主构造器
   *  def this(形参列表) { // 辅助构造器}
   * }
   * (1)未用任何修饰符修饰,这个参数就是一个局部变量
   * (2)var 修饰参数,作为类的成员属性使用,可以修改
   * (3)val 修饰参数,作为类只读属性使用,不能修改
   */
}
// 如果主构造器无参数,小括号可以省略,构建对象时调用的构造方法的小括号也可以省略
class Person7 {
  var name: String = _
  var age: Int = _
  def this(age: Int) {
    this()
    this.age = age
    println("辅助构造器")
  }
  def this(age: Int, name: String) {
    this(age)
    this.name = name
  }
  println("主构造器")
}

object Person7 {
  def main(args: Array[String]): Unit = {
    val person = new Person7(18)
  }
}

class Person77(name: String, var age: Int, val sex: String) {

}
object Test77 {
  def main(args: Array[String]): Unit = {
    var person = new Person77("bobo", 18, "男")
    person.age = 19
    println(person.age)
    println(person.sex)
  }
}

封装

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-4:45 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
class Test08_Encapsulation {
  /**
   * 封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。
   * Java 封装操作如下:
   * (1)将属性进行私有化
   * (2)提供一个公共的 set 方法,用于对属性赋值
   * (3)提供一个公共的 get 方法,用于获取属性的值
   * Scala 中的 public 属性,底层实际为 private,并通过 get 方法(obj.field())和 set 方法(obj.field_=(value))对其进行操作。
   * 所以 Scala 并不推荐将属性设为 private,再为其设置public 的 get 和 set 方法的做法。但由于很多 Java 框架都利用反射调用 getXXX 和
   * setXXX 方法,有时候为了和这些框架兼容,也会为 Scala 的属性设置 getXXX 和 setXXX 方法(通过@BeanProperty 注解实现)。
   */
}

继承&多态

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-4:47 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
class Test09_ExtendsPolymorphic {
  /**
   * 1、子类继承父类的属性和方法,Scala是单继承
   * 2、继承的调用顺序:父类构造器->子类构造器
   * 3、Scala中属性和方法都是动态绑定,而Java中只有方法为动态绑定
   * 4、多态:父类引用指向子类对象
   */
}

class Person9(nameParam: String) {
  var name = nameParam
  var age: Int = _

  def this(nameParam: String, ageParam: Int) {
    this(nameParam) // 直接调用主构造方法
    this.age = ageParam
    println("父类辅助构造器")
  }

  println("父类主构造器")
}

class Emp(nameParam: String, ageParam: Int) extends Person9(nameParam, ageParam) {
  var empNo: Int = _

  def this(nameParam: String, ageParam: Int, empNoParam: Int) {
    this(nameParam, ageParam)
    this.empNo = empNoParam
    println("子类的辅助构造器")
  }

  println("子类的主构造器")
}

object Test {
  def main(args: Array[String]): Unit = {
    new Emp("z3", 11, 1111)
    val teacher: Teacher99 = new Teacher99()
    println(teacher.name)
    teacher.hello()
    val teacher2: Person99 = new Teacher99
    println(teacher2.name)
    teacher2.hello()
  }
}

// 动态绑定
class Person99 {
  val name: String = "person"

  def hello(): Unit = {
    println("hello person")
  }
}

class Teacher99 extends Person99 {
  override val name: String = "teacher"

  override def hello(): Unit = {
    println("hello teacher")
  }
}

抽象方法

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-5:17 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
class Test10_AbstractClassMethod {
  /**
   * (1)定义抽象类:abstract class Person{} //通过 abstract 关键字标记抽象类
   * (2)定义抽象属性:val|var name:String //一个属性没有初始化,就是抽象属性
   * (3)定义抽象方法:def hello():String //只声明而没有实现的方法,就是抽象方法
   *
   * (1)如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类
   * (2)重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override。
   * (3)子类中调用父类的方法使用 super 关键字
   * (4)子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var。
   * 因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写
   *
   * 和 Java 一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。
   */
}

abstract class Person10 {
  val name: String
  def hello(): Unit
}

class Teacher10 extends Person10 {
  val name: String = "teacher"
  def hello(): Unit = {
    println("hello teacher")
  }
}

object Test10 {
  def main(args: Array[String]): Unit = {
    val person = new Person10 {
      override val name: String = "teacher"
      override def hello(): Unit = println("hello teacher")
    }
    person.hello()
  }
}

伴生对象

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-5:24 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
object Test11_AssociatedObject {
  /**
   * Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概念)。但是为了能够和Java语言交互(因为Java中有静态概念),
   * 就产生了一种特殊的对象来模拟类对象,该对象为单例对象。若单例对象名与类名一致,则称该单例对象这个类的伴生对象,这个类的所有“静态”内容都
   * 可以放置在它的伴生对象中声明。
   * (1)单例对象采用 object 关键字声明
   * (2)单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
   * (3)单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
   */
}

object Person11 {
  var country: String = "China"
}

class Person11 {
  var name: String = "bobo"
}

object Test11 {
  def main(args: Array[String]): Unit = {
    println(Person11.country)
  }
}

Apply方法

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-5:30 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
object Test12_Apply {
  /**
   * (1)通过伴生对象的 apply 方法,实现不使用 new 方法创建对象。
   * (2)如果想让主构造器变成私有的,可以在()之前加上 private。
   * (3)apply 方法可以重载。
   * (4)Scala 中 obj(arg)的语句实际是在调用该对象的 apply 方法,即 obj.apply(arg)。用以统一面向对象编程和函数式编程的风格。
   * (5)当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实时伴生对象的 apply 方法
   */
  def main(args: Array[String]): Unit = {
    val p1 = Person12()
    println("p1.name=" + p1.name)
    val p2 = Person12("bobo")
    println("p2.name=" + p2.name)
  }
}

class Person12 private(cName: String) {
  var name: String = cName
}

object Person12 {
  def apply(): Person12 = {
    println("apply空参被调用")
    new Person12("lotuslaw")
  }
  def apply(name: String): Person12 = {
    println("apply有参被调用")
    new Person12(name)
  }
}

特质

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-24-5:37 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
trait Test13_Trait {
  /**
   * Scala 语言中,采用特质 trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质(特征)时,就可以将这个特质(特征)独立出来,
   * 采用关键字 trait 声明。
   * Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入(mixin)多个特质。这种感觉类似于 Java 中的抽象类。
   * Scala 引入 trait 特征,第一可以替代 Java 的接口,第二个也是对单继承机制的一种补充。
   * 特质=抽象类+接口
   *
   * 一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了 extends 关键字,如果有多个特质或存在父
   * 类,那么需要采用 with关键字连接。
   * 没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 …
   * 有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3…
   *
   * (1)类和特质的关系:使用继承的关系。
   * (2)当一个类去继承特质时,第一个连接词是 extends,后面是 with。
   * (3)如果一个类在同时继承特质和父类时,应当把父类写在 extends 后。
   *
   * 由于一个类可以混入(mixin)多个 trait,且 trait 中可以有具体的属性和方法,若混入的特质中具有相同的方法(方法名,参数列表,返回值均相同),
   * 必然会出现继承冲突问题。冲突分为以下两种:
   * 第一种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且两个 trait 之间没有任何关系,解决这类冲突问题,
   * 直接在类(Sub)中重写冲突方法。
   * 第二种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且两个 trait 继承自相同的 trait(TraitC),
   * 即所谓的“钻石问题”,解决这类冲突问题,Scala采用了特质叠加的策略。
   *
   * 自身类型可以实现依赖注入的功能
   *
   * 使用 type 关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名
   *
   * 1.优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。
   * 2.如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行(有无参构造)。
   */
}

trait PersonTrait {
  // 特质可以同时拥有抽象方法和具体方法
  // 声明属性
  var name: String = _
  // 声明方法
  def eat(): Unit = {
    println("eat")
  }
  // 抽象属性
  var age: Int
  // 抽象方法
  def say(): Unit
}

trait Sextrait {
  var sex: String
}

// 一个类可以实现/继承多个特质
// 所有的Java接口都可以当做Scala特质使用
class Teacher13 extends PersonTrait with java.io.Serializable {
  override def say(): Unit = {
    println("say")
  }

  override var age: Int = _
}

trait Ball {
  def describe(): String = {
    "ball"
  }
}

trait Color extends Ball {
  override def describe(): String = {
    "blue" + super.describe()
  }
}

trait Category extends Ball {
  override def describe(): String = {
    "foot-" + super.describe()
  }
}

class MyBall extends Category with Color {
  override def describe(): String = {
    "My ball is a " + super.describe()
  }
}

class User(val name: String, val age: Int)

trait Dao {
  def insert(user: User) = {
    println("insert into database :" + user.name)
  }
}

trait App14 {
  // 语法:类似类的继承
  _: Dao =>
  def login(user: User): Unit = {
    println("login :" + user.name)
    insert(user)
  }
}

object TestTrait {
  def main(args: Array[String]): Unit = {
    val teacher = new Teacher13
    teacher.say()
    teacher.eat()
    // 动态混入:灵活扩展类的功能
    val t2 = new Teacher13 with Sextrait {
      override var sex: String = "男"
    }
    // 调用混入trait的属性
    println(t2.sex)

    /*
     * 第一步:列出混入的第一个特质(Category)的继承关系,作为临时叠加顺序
     * 第二步:列出混入的第二个特质(Color)的继承关系,并将该顺序叠加到临时顺序前边,已经出现的特质不再重复
     * 第三步:将子类(MyBall)放在临时叠加顺序的第一个,得到最终的叠加顺序
     * 如果想要调用某个指定的混入特质中的方法,可以增加约束:super[],例如super[Category].describe()。
     */
    println(new MyBall().describe())  // My ball is a bluefoot-ball

    type S = String
    var v: S = "abc"
    def test(): S = "XYZ"

    println(test())
  }
}

object MyApp extends App14 with Dao {
  def main(args: Array[String]): Unit = {
    login(new User("bobo", 19))
  }
}

object TestApp extends App {
  println("=========")
}

扩展

package com.lotuslaw.chapter06

/**
 * @author: lotuslaw
 * @create: 2021-07-25-3:12 下午
 * @package: com.lotuslaw.chapter06
 * @description:
 */
object Test14_ObjectExtension {
  /**
   * 枚举类:需要继承 Enumeration
   * 应用类:需要继承 App
   */
}

class Person14 {

}

object Person14 {
  def main(args: Array[String]): Unit = {
    val person = new Person14
    // 判断对象是否为某个类型的实例
    val bool: Boolean = person.isInstanceOf[Person14]
    if (bool) {
      // 将对象转换为某个类型的实例
      val p1: Person14 = person.asInstanceOf[Person14]
      println(p1)
    }
    // 获取类的信息
    val pClass: Class[Person14] = classOf[Person14]
    println(pClass)
  }
}

object Test14 {
  def main(args: Array[String]): Unit = {
    println(Color14.RED)
    println(Color14.YELLOW)
  }
}

// 定义枚举类对象
object Color14 extends Enumeration {
  val RED = Value(1, "red")
  val YELLOW = Value(2, "yellow")
  val BLUE = Value(3, "blue")
}

object APP14 extends App {

}

集合

集合概述

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-07-25-3:53 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test01_Summarize {
  /**
   * 1)Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable特质。
   * 2)对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两个包
   * 不可变集合:scala.collection.immutable
   * 可变集合: scala.collection.mutable
   * 3)Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于 java 中的 String 对象
   * 4)可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象
   * 建议:在操作集合的时候,不可变用符号,可变用方法
   * 不可变集合:
   * 1)Set、Map 是 Java 中也有的集合
   * 2)Seq 是 Java 没有的,我们发现 List 归属到 Seq 了,因此这里的 List 就和 Java 不是同一个概念了
   * 3)我们前面的 for 循环有一个 1 to 3,就是 IndexedSeq 下的 Range
   * 4)String 也是属于 IndexedSeq
   * 5)我们发现经典的数据结构比如 Queue 和 Stack 被归属到 LinearSeq(线性序列)
   * 6)大家注意 Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map 可以支持排序
   * 7)IndexedSeq 和 LinearSeq 的区别:
   * (1)IndexedSeq 是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集合,通过索引即可定位
   * (2)LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找
   * 可变集合
   *
   */
  def main(args: Array[String]): Unit = {
    val list = List(1,2,3)
    // :: 用于的是向队列的头部追加数据,产生新的列表, x::list,x就会添加到list的头部
    println(4 :: list)  //输出: List(4, 1, 2, 3)
    // .:: 这个是list的一个方法;作用和上面的一样,把元素添加到头部位置; list.::(x);
    println( list.:: (5)) //输出: List(5, 1, 2, 3)
    // :+ 用于在list尾部追加元素; list :+ x;
    println(list :+ 6)  //输出: List(1, 2, 3, 6)
    // +: 用于在list的头部添加元素;
    val list2 = "A"+:"B"+:Nil //Nil Nil是一个空的List,定义为List[Nothing]
    println(list2)  //输出: List(A, B)
    // ::: 用于连接两个List类型的集合 list ::: list2
    println(list ::: list2) //输出: List(1, 2, 3, A, B)
    // ++ 用于连接两个集合,list ++ list2
    println(list ++ list2) //输出: List(1, 2, 3, A, B)
  }
}

不可变数组

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-07-25-3:58 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test02_ImmutableArray {
  def main(args: Array[String]): Unit = {
    // 数组定义
    var arr01 = new Array[Int](4)
    println(arr01.length)
    // 数组赋值
    // 修改某个元素的值
    arr01(3) = 10
    // 采用方法的形式给数组赋值
    arr01.update(0, 1)
    // 遍历数组
    // 查看数组
    println(arr01.mkString(","))
    // 普通遍历
    for (i <- arr01) {
      println(i)
    }
    // 简化遍历
    def printx(elem: Int): Unit = {
      println(elem)
    }
    arr01.foreach(printx)
    arr01.foreach(println)
    // 增加元素,由于创建的是不可变数组,增加元素,其实是产生新的数组
    println(arr01)
    val ints: Array[Int] = arr01 :+ 5
    println(ints)

    var arr02 = Array(1, 3, "bobo")
    println(arr02.length)
    for (elem <- arr02) {
      println(elem)
    }
  }
}

可变数组

package com.lotuslaw.chapter07

import scala.collection.mutable.ArrayBuffer

/**
 * @author: lotuslaw
 * @create: 2021-07-25-5:11 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test03_ArrayBuffer {
  def main(args: Array[String]): Unit = {
    // 创建并初始赋值可变数组
    val arr01 = ArrayBuffer[Any](1, 2, 3)
    // 遍历数组
    for (elem <- arr01) {
      println(elem)
    }
    println(arr01.length)
    println("arr01.hash=" + arr01.hashCode())
    // 增加元素
    // 追加元素
    arr01.+=(4)
    // 向数组最后追加数据
    arr01.append(5, 6)
    // 向指定的位置插入数据
    arr01.insert(0, 7, 8)
    println(arr01.mkString(","))
    println("arr01.hash=" + arr01.hashCode())
    // 修改元素
    arr01(0) = 9
    println("==========")
    for (elem <- arr01) {
      println(elem)
    }
    println(arr01.length)
    // 移除元素
    arr01.remove(0, 2)
    println(arr01.mkString(","))

    // 创建一个空的可变数组
    val arr02 = ArrayBuffer[Int]()
    // 追加值
    arr02.append(1, 2, 3)
    println(arr02)
    // ArrayBuffer ==>  Array
    // arr02.toArray 返回的结果是一个新的定长数组集合
    // arr02它没有变化
    val newArr = arr02.toArray
    println(newArr)
    // Array ==> ArrayBuffer
    // newArr.toBuffer 返回的是一个变长数组newArr2
    // newArr 没有任何变化,依然是定长数组
    val newArr2 = newArr.toBuffer
    newArr2.append(123)
    println(newArr2)
  }
}

多维数组

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-07-25-5:23 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test04_DimArray {
  def main(args: Array[String]): Unit = {
    // 创建了一个二维数组,有三个元素,每个元素是含有4个元素的一维数组
    val arr = Array.ofDim[Int](3, 4)
    arr(1)(2) = 88
    // 遍历二维数组
    for (elem1 <- arr) {
      for (elem2 <- elem1) {
        print(elem2 + " ")
      }
      println()
    }
  }
}

不可变List

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-07-25-5:27 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test05_List {
  def main(args: Array[String]): Unit = {
    // List默认为不可变集合
    // 创建一个List(数据有顺序,可重复)
    val list: List[Int] = List(1, 2, 3, 4, 2)
    println(list.mkString(","))
    // 空结合Nil
    val list5 = 1::2::3::4::Nil
    println(list5.mkString(","))
    // List增加数据
    // ::的运算规则从右向左
    // val list1 = 5::list
    val list1 = 7::6::5::list
    println(list1.mkString(","))
    // 添加到第一个元素位置
    val list2 = list.+:(5)
    println(list2.mkString(","))
    // 集合间合并:将一个整体拆成一个一个的个体,称为扁平化
    val list3 = List(8, 9)
    println(list3.mkString(","))
    val list4 = list3:::list1
    println((list3::list1).mkString(","))
    println(list4.mkString(","))
    // 取指定数据
    println(list(0))
  }
}

可变List

package com.lotuslaw.chapter07

import scala.collection.mutable.ListBuffer

/**
 * @author: lotuslaw
 * @create: 2021-07-25-5:35 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test06_ListBuffer {
  def main(args: Array[String]): Unit = {
    // 创建一个可变集合
    val buffer = ListBuffer(1, 2, 3, 4)
    // 向集合中添加数据
    buffer.+=(5)
    buffer.append(6)
    buffer.insert(1, 2)
    println(buffer.mkString(","))
    println(buffer)
    // 修改数据
    buffer(1) = 6
    buffer.update(1, 7)
    // 删除数据
    // buffer.-(5)  // 不起作用
    println(buffer.mkString(","))
    buffer.-=(5)
    println(buffer.mkString(","))
    buffer.remove(5)
    println(buffer.mkString(","))
  }
}

Set

package com.lotuslaw.chapter07

import scala.collection.mutable

/**
 * @author: lotuslaw
 * @create: 2021-07-25-5:40 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test06_Set {
  def main(args: Array[String]): Unit = {
    // Set默认是不可变集合,数据无序
    val set = Set(1, 2, 3, 4, 5, 6)
    // 数据不可以重复
    val set1 = Set(1, 3, 4, 4, 5, 2, 1)
    for (elem <- set1) {
      println(elem)
    }
    println(set1.mkString(","))

    // 创建可变集合
    val set2 = mutable.Set(1, 2, 3, 4, 5, 6)
    // 集合添加元素
    set2 += 8
    // 向集合中添加元素,返回一个新的Set
    val ints = set2.+(9)
    println(ints)
    println("set2=" + set2)
    // 删除数据
    set2 -= (5)
    println(set2.mkString(","))
  }
}

Map

package com.lotuslaw.chapter07

import scala.collection.mutable

/**
 * @author: lotuslaw
 * @create: 2021-07-25-5:45 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test07_Map {
  def main(args: Array[String]): Unit = {
    // Map
    // 创建不可变集合Map
    val map = Map("a"->1, "b"->2, "c"->3)
    // 访问数据
    for (elem <- map.keys) {
      // 使用get访问map集合的数据,会返回特殊类型Option(选项):有值(Some),无值(None)
      println(elem + "=" + map.get(elem).get)
    }
    // 如果key不存在,返回0
    println(map.get("d").getOrElse(0))
    println(map.getOrElse("d", 0))
    // 循环打印
    map.foreach((kv) => {println(kv)})
    println(map.mkString(","))
    println(map)
    map.foreach(println)

    // 创建可变集合
    val map2 = mutable.Map("a"->1, "b"->2, "c"->3)
    // 向集合增加元素
    map2.+=("d"->4)
    // 将数值4添加到集合,并把集合中原值1返回
    val maybeInt: Option[Int] = map2.put("a", 4)
    println(maybeInt.getOrElse(0))
    // 删除数据
    map2.-=("b", "c")
    println(map2)
    // 修改数据
    map2.update("d", 5)
    println(map2)
    map2("d") = 6
    println(map2)
    // 打印集合
    map2.foreach(println)
  }
}

元组

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-08-01-8:14 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test08_Tuple {
  def main(args: Array[String]): Unit = {
    /**
     * 元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组。
     * 注意:元组中最大只能有 22 个元素。
     */
    // 声明元组的方式:(元素1,元素2,元素3)
    val tuple: (Int, String, Boolean) = (40, "bobo", true)
    // 访问元组
    // 通过元素的顺序进行访问,调用方式:_顺序号
    println(tuple._1)
    println(tuple._2)
    println(tuple._3)
    // 通过索引访问数据
    println(tuple.productElement(0))
    println(tuple.productElement(1))
    println(tuple.productElement(2))
    // 通过迭代器访问数据
    for (elem <- tuple.productIterator) {
      println(elem)
    }
    // Map中的键值对其实就是元组,只不过元组的元素个数为2,称之为对偶
    val map = Map("a" -> 1, "b" -> 2, "c" -> 3)
    val map1 = Map(("a", 1), ("b", 2), ("c", 3))
    map.foreach(tuple => {println(tuple._1 + "=" + tuple._2 )})
    map1.foreach(tuple => {println(tuple._1 + "=" + tuple._2 )})
  }
}

集合基本操作

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-08-01-8:23 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test09_BaseOperation {
  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
    // 获取集合长度
    println(list.length)
    // 获取集合大小,等同于length
    println(list.size)
    // 循环遍历
    list.foreach(println)
    // 迭代器
    for (elem <- list.iterator) {
      println(elem)
    }
    // 生成字符串
    println(list.mkString(","))
    // 是否包含
    println(list.contains(3))
  }
}

衍生集合

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-08-01-8:27 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test10_DeriveSet {
  def main(args: Array[String]): Unit = {
    val list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
    val list2: List[Int] = List(4, 5, 6, 7, 8, 9, 10)
    // 获取集合的头
    println(list1.head)
    // 获取集合的尾(不是头的就是尾)
    println(list1.tail)
    // 集合最后一个数据
    println(list1.last)
    // 集合初始数据(不包含最后一个)
    println(list1.init)
    // 反转
    println(list1.reverse)
    // 取前(后)n个元素
    println(list1.take(3))
    println(list1.takeRight(3))
    // 去掉前(后)n个元素
    println(list1.drop(3))
    println(list1.dropRight(3))
    // 并集
    println(list1.union(list2))
    // 交集
    println(list1.intersect(list2))
    // 差集
    println(list1.diff(list2))
    // 拉链(注意,如果两个集合的元素个数不相等,那么会将同等数量的数据进行拉链,多余的数据省略不用)
    println(list1.zip(list2))
    // 滑窗
    list1.sliding(2, 5).foreach(println)
  }
}

集合简单计算函数

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-08-01-8:39 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test11_EasyCompute {
  def main(args: Array[String]): Unit = {
    /**
     * (1)sorted
     * 对一个集合进行自然排序,通过传递隐式的 Ordering
     * (2)sortBy
     * 对一个属性或多个属性进行排序,通过它的类型。
     * (3)sortWith
     */
    val list: List[Int] = List(1, 5, -3, 4, 2, -7, 6)
    // 求和
    println(list.sum)
    // 求乘积
    println(list.product)
    // 最大值
    println(list.max)
    // 最小值
    println(list.min)
    // 排序
    // 按照元素大小排序
    println(list.sortBy(x => x))
    // 按照元素的绝对值大小排
    println(list.sortBy(x => x.abs))
    // 按照元素大小升序排序
    println(list.sortWith((x, y) => x < y))
    // 按照元素大小降序排序
    println(list.sortWith((x, y) => x > y))
  }
}

集合高级计算函数

package com.lotuslaw.chapter07

import scala.collection.mutable

/**
 * @author: lotuslaw
 * @create: 2021-08-01-8:45 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test12_AdvancedFunction {
  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
    val nestedList: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
    val wordList: List[String] = List("hello world", "hello lotuslaw", "hello scala")
    // 过滤
    println(list.filter(x => x % 2 == 0))
    // 转化、映射
    println(list.map(x => x + 1))
    // 扁平化
    println(nestedList.flatten)
    // 扁平化+映射
    println(wordList.flatMap(x => x.split(" ")))
    // 分组
    println(list.groupBy(x => x % 2))
    // Reduce 简化(归约) :通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最终获取结果
    val i: Int = list.reduce((x, y) => x - y)
    println(i)
    // 从源码的角度,reduce 底层调用的其实就是 reduceLeft
    ////val i1 = list.reduceLeft((x,y) => x-y)
    // ((4-3)-2-1) = -2
    val i2 = list.reduceRight((x,y) => x-y)
    println(i2)
    // Fold折叠:化简的一种特殊情况
    // fold 方法使用了函数柯里化,存在两个参数列表
    // 第一个参数列表为 : 零值(初始值)
    // 第二个参数列表为: 简化规则
    // fold 底层其实为 foldLeft
    val j = list.foldLeft(1)((x, y) => x - y)
    println(j)
    val j1 = list.foldRight(10)((x, y) => x - y)
    println(j1)
    // 两个Map的数据合并
    val map1 = mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)
    val map2 = mutable.Map("a" -> 4, "b" -> 5, "d" -> 6)
    val map3: mutable.Map[String, Int] = map2.foldLeft(map1) {
      (map, kv) => {
        println(map)  // 每一轮的map2
        println(kv)  // 每一轮map1的kv
        val k = kv._1
        val v = kv._2
        map(k) = map.getOrElse(k, 0) + v
        map
      }
    }
  }
}

WordCount

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-08-01-9:05 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test13_EasyWordCount {
  def main(args: Array[String]): Unit = {
    // 单词计数:将集合中出现的相同的单次,进行计数,取计数排名前三的结果
    val stringList = List("Hello Scala Hbase kafka", "Hello Scala Hbase", "Hello Scala", "Hello")
    // 将每一个字符串转换成一个一个单词
    val wordList: List[String] = stringList.flatMap(x => x.split(" "))
    // 将相同的单次放置在一起
    val wordToWordsMap: Map[String, List[String]] = wordList.groupBy(word => word)
    // 对相同的单次进行计数
    val wordToCountMap: Map[String, Int] = wordToWordsMap.map(tuple => (tuple._1, tuple._2.size))
    // 对计数完成后的结果进行排序(降序)
    val sortList: List[(String, Int)] = wordToCountMap.toList.sortWith {
      (Left, Right) => {
        Left._2 > Right._2
      }
    }
    // 对排序的结果取前3名
    val resultList: List[(String, Int)] = sortList.take(3)
    println(resultList)
  }
}
package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-08-01-9:18 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test14_ComplexWordCount {
  def main(args: Array[String]): Unit = {
    /*
    // 第一种方式(不通用)
    val tupleList = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1))
    val stringList: List[String] = tupleList.map(t => (t._1 + " ") * t._2)
    val words: List[String] = stringList.flatMap(_.split(" "))
    // 在map中,如果传进来什么就返回什么,不要用_省略
    val groupMap: Map[String, List[String]] = words.groupBy(word => word)
    val wordToCount: Map[String, Int] = groupMap.map(t => (t._1, t._2.size))
    val wordCountList: List[(String, Int)] = wordToCount.toList.sortWith {
      (left, right) => {
        left._2 > right._2
      }
    }.take(3)
    println(wordCountList)
    */
    val tupleList = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1))
    val wordCountList = tupleList
      .map(t => (t._1 + "") * t._2)
      .flatMap(_.split(" "))
      .groupBy(word => word)
      .map(t => (t._1, t._2.size))
    println(wordCountList)
  }
}
package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-08-01-9:30 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test15_ComplexWordCount2 {
  def main(args: Array[String]): Unit = {
    val tuples = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1))
    val wordToCountList: List[(String, Int)] = tuples.flatMap {
      t => {
        val strings: Array[String] = t._1.split(" ")
        strings.map(word => (word, t._2))
      }
    }
    val wordToTupleMap: Map[String, List[(String, Int)]] = wordToCountList.groupBy(t => t._1)
    val stringToInts: Map[String, List[Int]] = wordToTupleMap.mapValues {
      datas => datas.map(t => t._2)
    }
    val wordToTotalCountMap: Map[String, Int] = stringToInts.map(t => (t._1, t._2.sum))
    println(wordToTotalCountMap)
  }
}

队列

package com.lotuslaw.chapter07

import scala.collection.mutable

/**
 * @author: lotuslaw
 * @create: 2021-08-01-9:54 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test16_Queue {
  def main(args: Array[String]): Unit = {
    val que = new mutable.Queue[String]()
    que.enqueue("a", "b", "c")
    println(que.dequeue())
    println(que.dequeue())
    println(que.dequeue())
  }
}

并行集合

package com.lotuslaw.chapter07

/**
 * @author: lotuslaw
 * @create: 2021-08-01-9:55 下午
 * @package: com.lotuslaw.chapter07
 * @description:
 */
object Test17_Parallel {
  def main(args: Array[String]): Unit = {
    val result1 = (0 to 100).map {
      case _ => Thread.currentThread.getName
    }
    val result2 = (0 to 100).par.map {
      case _ => Thread.currentThread.getName
    }
    println(result1)
    println(result2)
  }
}

模式匹配

基本语法

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-11:17 上午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test01_MatchCase {
  def main(args: Array[String]): Unit = {
    /**
     * (1)如果所有 case 都不匹配,那么会执行 case _ 分支,类似于 Java 中 default 语句,若此时没有 case _ 分支,那么会抛出 MatchError。
     * (2)每个 case 中,不需要使用 break 语句,自动中断 case。
     * (3)match case 语句可以匹配任何类型,而不只是字面量。
     * (4)=> 后面的代码块,直到下一个 case 语句之前的代码是作为一个整体执行,可以使用{}括起来,也可以不括。
     */
    var a: Int = 10
    var b: Int = 20
    var operator: Char = 'd'
    var result = operator match {
      case '+' => a + b
      case '-' => a - b
      case '*' => a * b
      case '/' => a / b
      case _ => "illegal"
    }
    println(result)
  }
}

模式匹配守卫

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-11:22 上午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test02_MatchGuard {
  def main(args: Array[String]): Unit = {
    def abs(x: Int) = x match {
      case i: Int if i >= 0 => i
      case j: Int if j < 0 => -j
      case _ => "type illegal"
    }
    println(abs(-5))
  }
}

匹配常量

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-11:26 上午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test03_MatchVal {
  def main(args: Array[String]): Unit = {
    // Scala 中,模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等等。
    println(describe(5))
    def describe(x: Any) = x match {
      case 5 => "Int five"
      case "hello" => "String hello"
      case true => "Boolean true"
      case '+' => "Char +"
      case _ => "other"
    }
  }
}

匹配类型

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-11:29 上午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test04_MatchClass {
  def describe(x: Any) = x match {
    case i: Int => "Int"
    case s: String => "String Hello"
    case m: List[_] => "List"
    case c: Array[Int] => "Array[Int]"
    case someThing => "something else" + someThing
  }
  def main(args: Array[String]): Unit = {
    // 需要进行类型判断时,可以使用前文所学的 isInstanceOf[T]和 asInstanceOf[T],也可使用模式匹配实现同样的功能。
    // 泛型擦除
    println(describe(List(1, 2, 3, 4, 5)))
    // 数组例外,可保留泛型
    println(describe(Array(1, 2, 3, 4, 5, 6)))
    println(describe(Array("abc")))
  }
}

匹配数组

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-12:00 下午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test05_MatchArray {
  def main(args: Array[String]): Unit = {
    // scala 模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素为 0 的数组。
    for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0), Array(1, 1, 0), Array(1, 1, 0, 1), Array("hello", 90))) {
      val result = arr match {
        case Array(0) => "0"
        case Array(x, y) => x + "," + y
        case Array(0, _*) => "以0开头的数组"
        case _ => "something else"
      }
      println("result" + result)
    }
  }
}

匹配List

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-12:06 下午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test06_MatchList {
  def main(args: Array[String]): Unit = {
    // list 是一个存放 List 集合的数组
    // 请思考,如果要匹配 List(88) 这样的只含有一个元素的列表,并原值返回.应该怎么写
    for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0), List(88))) {
      val result = list match {
        case List(0) => "0"
        case List(x, y) => x + "," + y
        case List(0, _*) => "0 ..."
        case _ => "something else"
      }
      println(result)
    }
    val list: List[Int] = List(1, 2, 5, 6, 7)
    list match {
      case first :: second :: rest => println(first + "-" + second + "-" + rest)  // 向rest列表的头部加second,再向头部加first
      case _ => println("something else")
    }
  }
}

匹配元组

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-12:18 下午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test07_MatchTuple {
  def main(args: Array[String]): Unit = {
    for (tuple <- Array((0, 1), (1, 0), (1, 1), (1, 0, 2))) {
      val result = tuple match {
        case (0, _) => "0 ..."
        case (y, 0) => "" + y + "0"
        case (a, b) => "" + a + " " + b
        case _ => "something else"
      }
      println(result)
    }
  }
}

特殊模式匹配例子

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-12:22 下午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test08_SpecialExample {
  def main(args: Array[String]): Unit = {
    // 特殊的模式匹配 1 打印元组第一个元素
    for (elem <- Array(("a", 1), ("b", 2), ("c", 3))) {
      println(elem._1)
    }
    for ((word, count) <- Array(("a", 1), ("b", 2), ("c", 3))) {
      println(word)
    }
    for (("a", count) <- Array(("a", 1), ("b", 2), ("c", 3))) {
      println(count)
    }
    // 特殊的模式匹配 2 给元组元素命名
    var (id, name, age): (Int, String, Int) = (100, "lotuslaw", 18)
    println((id, name, age))
    // 特殊的模式匹配 3 遍历集合中的元组,给 count * 2
    var list: List[(String, Int)] = List(("a", 1), ("b", 2), ("c", 3))
    println(
      list.map {
        case (word, count) => (word, count * 2)
      }
    )
    var list1 = List(("a", ("a", 1)), ("b", ("b", 2)), ("c", ("c", 3)))
    println(list1.map {
      case (groupKey, (word, count)) => (word, count * 2)
    })
  }
}

匹配对象

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-12:37 下午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test09_MatchObject {
  def main(args: Array[String]): Unit = {
    /**
     * val user = User("lotuslaw",18),该语句在执行时,实际调用的是 User 伴生对象中的apply 方法,因此不用 new 关键字就能构造出相应的对象
     * 当将 User("lotuslaw",18)写在 case 后时[case User("lotuslaw",18) => "yes"],会默认调用 unapply 方法(对象提取器),user 作为
     * unapply 方法的参数,unapply 方法将 user 对象的 name 和 age 属性提取出来,与 User("lotuslaw",18)中的属性值进行匹配
     * case 中对象的 unapply 方法(提取器)返回 Some,且所有属性均一致,才算匹配成功,属性不一致,或返回 None,则匹配失败。
     * 若只提取对象的一个属性,则提取器为 unapply(obj:Obj):Option[T]
     * 若提取对象的多个属性,则提取器为 unapply(obj:Obj):Option[(T1,T2,T3…)]
     * 若提取对象的可变个属性,则提取器为 unapplySeq(obj:Obj):Option[Seq[T]]
     */
    val user: User = User("lotuslaw", 18)
    val result = user match {
      case User("lotuslaw", 18) => "yes"
      case _ => "no"
    }
    println(result)
  }
}

class User(val name: String, val age: Int)

object User {
  def apply(name: String, age: Int): User = new User(name, age)
  def unapply(user: User): Option[(String, Int)] = {
    if (user == null)
      None
    else
      Some(user.name, user.age)
  }
}

样例类

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-12:46 下午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test10_CaseObject {
  def main(args: Array[String]): Unit = {
    /**
     * 1 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如 apply、unapply、toString、equals、hashCode 和 copy。
     * 2 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例类可以直接使用模式匹配,而无需自己实现 unapply 方法。
     * 3 构造器中的每一个参数都成为 val,除非它被显式地声明为 var(不建议这样做)
     */
    val user: User10 = User10("lotuslaw", 18)
    val result = user match {
      case User10("lotuslaw", 18) => "yes"
      case _ => "no"
    }
    println(result)
  }
}

case class User10(name: String, age: Int)

匹配变量

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-12:49 下午
 * @package: com.lotuslaw.chapter08
 * @description: 变量声明中的模式匹配
 */
object Test11_MatchVariable {
  def main(args: Array[String]): Unit = {
    val (x, y) = (1, 2)
    println(s"x=$x, y=$y")
    val Array(first, second, _*) = Array(1, 7, 2, 9)
    println(s"first=$first,second=$second")
    val Person11(name, age) = Person11("lotuslaw", 18)
    println(s"name=$name, age=$age")
  }
}

case class Person11(name: String, age: Int)

for循环匹配

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-1:02 下午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test12_MatchFor {
  def main(args: Array[String]): Unit = {
    val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
    for ((k, v) <- map) {
      println(k + "->" + v)
    }
    for ((k, 0) <- map) {
      println(k + "->" + 0)
    }
    for ((k, v) <- map if v >= 1) {
      println(k + "->" + v)
    }
  }
}

偏函数

package com.lotuslaw.chapter08

/**
 * @author: lotuslaw
 * @create: 2021-08-08-1:33 下午
 * @package: com.lotuslaw.chapter08
 * @description:
 */
object Test13_PartialFunction {
  def main(args: Array[String]): Unit = {
    /**
     * 偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。例如该偏函数的输入类型为 List[Int],
     * 而我们需要的是第一个元素是 0 的集合,这就是通过模式匹配实现的。
     */
    // 该偏函数的功能是返回输入的 List 集合的第二个元素
    val second: PartialFunction[List[Int], Option[Int]] = {
      case x :: y :: _ => Some(y)
    }
    // 上述代码会被 scala 编译器翻译成以下代码,与普通函数相比,只是多了一个用于参数检查的函数——isDefinedAt,其返回值类型为 Boolean。
    /*
    val second = new PartialFunction[List[Int], Option[Int]] {
      // 检查输入参数是否合格
      override def isDefinedAt(list: List[Int]): Boolean = list match {
        case x :: y :: _ => true
        case _ => false
      }

      // 执行函数逻辑
      override def apply(list: List[Int]): Option[Int] = list match {
        case x :: y :: _ => Some(y)
      }
    }
     */
    // 偏函数不能像 second(List(1,2,3))这样直接使用,因为这样会直接调用 apply 方法,而应该调用 applyOrElse 方法,如下
    // applyOrElse 方法的逻辑为 if (ifDefinedAt(list)) apply(list) else default。如果输入参数满足条件,即 isDefinedAt 返回 true,
    // 则执行 apply 方法,否则执行 defalut 方法,default 方法为参数不满足要求的处理逻辑。
    println(second.applyOrElse(List(1, 2, 3), (_: List[Int]) => None))
    // 将该 List(1,2,3,4,5,6,"test")中的 Int 类型的元素加一,并去掉字符串
    val list = List(1,2,3,4,5,6,"test")
    val list1 = list.map {
      a => {
        a match {
          case i: Int => i + 1
          case s: String => s + 1
        }
      }
    }
    println(list1.filter(a => a.isInstanceOf[Int]))
    List(1,2,3,4,5,6,"test").filter(_.isInstanceOf[Int]).map(_.asInstanceOf[Int] + 1).foreach(println)
    List(1,2,3,4,5,6,"test").collect{case x: Int => x + 1}.foreach(println)
  }
}

异常

package com.lotuslaw.chapter09

/**
 * @author: lotuslaw
 * @create: 2021-08-08-1:51 下午
 * @package: com.lotuslaw.chapter09
 * @description:
 */
object Test01_Summarize {
  def main(args: Array[String]): Unit = {
    /**
     * 1)我们将可疑代码封装在 try 块中。在 try 块之后使用了一个 catch 处理程序来捕获异常。如果发生任何异常,catch 处理程序将处理它,程序将不会异常终止。
     * 2)Scala 的异常的工作机制和 Java 一样,但是 Scala 没有“checked(编译期)”异常,即 Scala 没有编译异常这个概念,异常都是在运行的时候捕获处理。
     * 3)异常捕捉的机制与其他语言中一样,如果有异常发生,catch 子句是按次序捕捉的。因此,在 catch 子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异
     * 常写在前,把具体的异常写在后,在 Scala 中也不会报错,但这样是非常不好的编程风格。
     * 4)finally 子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和 Java 一样。
     * 5)用 throw 关键字,抛出一个异常对象。所有异常都是 Throwable 的子类型。throw 表达式是有类型的,就是 Nothing,因为 Nothing 是所有类型的子类型,
     * 所以 throw 表达式可以用在需要类型的地方
     * 6)java 提供了 throws 关键字来声明异常。可以使用方法定义声明异常。它向调用者函数提供了此方法可能引发此异常的信息。它有助于调用函数处理并将该代码包含在 try-catch
     * 块中,以避免程序异常终止。在 Scala 中,可以使用 throws 注解来声明异常
     */
    try {
      var n = 10 / 0
    } catch {
      case ex: ArithmeticException => {
        println("发生算数异常")
      }
      case ex: Exception => {
        println("发生了异常1")
        println("发生了异常2")
      }
    } finally {
      println("finally")
    }
    try {
      f_test()
    } catch {
      case ex: Exception => {
        println("Exception")
      }
    }
    println("----------")
  }

  def test(): Nothing = {
    throw new Exception("不对")
  }
  @throws(classOf[NumberFormatException])
  def f_test() = {
    "abc".toInt
  }
}

隐式转换

隐式函数

package com.lotuslaw.chapter10

/**
 * @author: lotuslaw
 * @create: 2021-08-08-2:04 下午
 * @package: com.lotuslaw.chapter10
 * @description:
 */
object Test01_ImplicitFunction {
  def main(args: Array[String]): Unit = {
    /**
     * 当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译
     */
    // 隐式转换可以在不需改任何代码的情况下,扩展某个类的功能
    // 使用 implicit 关键字声明的函数称之为隐式函数
    // 当想调用对象功能时,如果编译错误,那么编译器会尝试在当前作用域范围内查找能调用对应功能的转换规则,这个调用过程是由编译器完成的,所以称之为隐
    // 式转换。也称之为自动转换
    println(2.myMax(6))
  }
  implicit def convert(arg: Int): MyRichInt = {
    new MyRichInt(arg)
  }
}


class MyRichInt(val self: Int) {
  def myMax(i: Int): Int = {
    if (self < i) i else self
  }
  def myMin(i: Int) = {
    if (self < i) self else i
  }
}

隐式参数

package com.lotuslaw.chapter10

/**
 * @author: lotuslaw
 * @create: 2021-08-08-2:20 下午
 * @package: com.lotuslaw.chapter10
 * @description:
 */
object Test02_ImplicitParameter {
  /**
   * 普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时,就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。
   * (1)同一个作用域中,相同类型的隐式值只能有一个
   * (2)编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。
   * (3)隐式参数优先于默认参数
   */
  implicit val str: String = "hello world"
  def hello(implicit arg: String="good bye world"): Unit = {println(arg)}

  def main(args: Array[String]): Unit = {
    hello
  }
}

隐式类

package com.lotuslaw.chapter10

/**
 * @author: lotuslaw
 * @create: 2021-08-08-2:22 下午
 * @package: com.lotuslaw.chapter10
 * @description:
 */
object Test03_ImplicitClass {
  implicit class MyRichInt(arg: Int) {
    def myMax(i: Int): Int = {
      if (arg < i) i else arg
    }
    def myMin(i: Int): Int = {
      if (arg < i) arg else i
    }
  }

  def main(args: Array[String]): Unit = {
    /**
     * 在 Scala2.10 后提供了隐式类,可以使用 implicit 声明类,隐式类的非常强大,同样可以扩展类的功能,在集合中隐式类会发挥重要的作用。
     * (1)其所带的构造参数有且只能有一个
     * (2)隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的。
     */
    println(1.myMax(3))
  }
}

隐式解析机制

package com.lotuslaw.chapter10

import com.lotuslaw.chapter10.Test04_ImplicitParseMechanism.Teacher


/**
 * @author: lotuslaw
 * @create: 2021-08-08-2:30 下午
 * @package: com.lotuslaw.chapter10
 * @description:
 */
object Test04_ImplicitParseMechanism extends PersonTrait {
  def main(args: Array[String]): Unit = {
    /**
     * (1)首先会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)。(一般是这种情况)
     * (2)如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。类型的作用域是指与该类型相关联的全部伴生对象以及该类型所在包的包对象。
     */
    val teacher = new Teacher()
    teacher.eat()
    teacher.say()
  }
  class Teacher {
    def eat(): Unit = {
      println("eat ...")
    }
  }
}

trait PersonTrait {}
object PersonTrait {
  // 隐式类: 类型1 => 类型2
  implicit class Person04(user: Teacher) {
    def say(): Unit = {
      println("say ...")
    }
  }
}

泛型

协变和逆变

package com.lotuslaw.chapter11

/**
 * @author: lotuslaw
 * @create: 2021-08-08-2:36 下午
 * @package: com.lotuslaw.chapter11
 * @description:
 */
object Test01_CovariantContravariant {
  def main(args: Array[String]): Unit = {
    /**
     * class MyList[+T]{}  // 协变
     * class MyList[-T]{}  // 逆变
     * class MyList[T]  // 不变
     * 协变:Son 是 Father 的子类,则 MyList[Son] 也作为 MyList[Father]的“子类”。
     * 逆变:Son 是 Father 的子类,则 MyList[Son]作为 MyList[Father]的“父类”。
     * 不变:Son 是 Father 的子类,则 MyList[Father]与 MyList[Son]“无父子关系”。
     */
    var s: MyList[Child] = new MyList[SubChild]
    println(s.getClass.getName)
  }
}

// 泛型模板
// class MyList<T>{}
// 不变
// class MyList[T]{}
// 协变
 class MyList[+T]{}
// 逆变
// class MyList[-T]{}
class Parent {}
class Child extends Parent {}
class SubChild extends Child {}

泛型上下限

package com.lotuslaw.chapter11

/**
 * @author: lotuslaw
 * @create: 2021-08-08-2:43 下午
 * @package: com.lotuslaw.chapter11
 * @description:
 */
object Test02_GenericsUpperLowerLimits {
  def main(args: Array[String]): Unit = {
    /**
     * 泛型的上下限的作用是对传入的泛型进行限定。
     * Class PersonList[T <: Person]{}  // 泛型上限
     * Class PersonList[T >: Person]{}  // 泛型下限
     */
//    test[Child11_02](classOf[Child11_02])
    test[Parent11_02](new Child11_02)
    // 泛型通配符之上限
//    def test[A <: Child11_02](a: Class[A]): Unit = {
//      println(a)
//    }
    // 泛型通配符之下限
    //  def test[A >: Child11_02](a: Class[A]): Unit = {
    //    println(a)
    //  }
    // 泛型通配符之下限 形式扩展
      def test[A >: Child11_02](a: A): Unit = {
        println(a.getClass.getName)
      }
  }
}

class Parent11_02 {}
class Child11_02 extends Parent11_02 {}
class SubChild11_02 extends Child11_02 {}

上下文限定

package com.lotuslaw.chapter11

/**
 * @author: lotuslaw
 * @create: 2021-08-08-3:07 下午
 * @package: com.lotuslaw.chapter11
 * @description:
 */
object Test03_ContextLimitation {
  /**
   * def f[A : B](a: A) = println(a) //等同于 def f[A](a:A)(implicit arg:B[A])=println(a)
   * 上下文限定是将泛型和隐式转换的结合产物,以下两者功能相同,使用上下文限定[A :Ordering]之后,方法内无法使用隐式参数名调用隐式参数,
   * 需要通过 implicitly[Ordering[A]]获取隐式变量,如果此时无法查找到对应类型的隐式变量,会发生出错误。
   * implicit val x = 1
   * val y = implicitly[Int]
   * val z = implicitly[Double]
   *
   * def f[A:Ordering](a:A,b:A) =implicitly[Ordering[A]].compare(a,b)
   * def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)
   */
}
posted @ 2021-08-08 16:15  lotuslaw  阅读(74)  评论(0编辑  收藏  举报