美文网首页
Scala基础语法 二

Scala基础语法 二

作者: 八爪鱼下水 | 来源:发表于2021-03-23 19:40 被阅读0次

    1. 样例类

    简介:
    类似java中的实体类

    case class 样例类名([var/val] 成员变量名1:
    类型1, 成员变量名2:类型2, 成员变量名3:类型3)
    样例类的方法:
    

    apply方法

    可以让我们快速使用类名创建对象

    case class CasePerson(name:String, age:Int)
    
    object CaseClassDemo {
      def main(args: Array[String]): Unit = {
        val lisi = CasePerson("李四", 21)
        println(lisi.toString)
      }
    }
    

    unapply方法

    让我们可以通过模式匹配来获取类属性,是Scala中抽取器的实现和模式匹配 的关键方法
    又叫解构器
    就是将对象中的各个属性值,分别提取出来。底层是依赖unapply方法。

    override def unapply(stu:Student):Option[(类型1, 类型2, 类型3...)] = { if(stu != null) {
    Some((变量1, 变量2, 变量3...)) }
    else { None
    } }
    
    /**
     * @program: sz22scala
     * @description
     * @author: chenjia868
     * @create: 2021-03-23 14:46
     * */
    object Demo16Extractor { //创建一个Student类,包含姓名年龄两个字段
    class Student (var name:String,var age:Int) //定义半生对象,重写unapply方法,实现一个类的解构器, object Student{
        def unapply(stu:Student)={
          if(stu!=null){
            Some(Tuple2(stu.name,stu.age))
          }else{
    None }
    } }
    def main(args: Array[String]): Unit = { //并使用match表达式进行模式匹配,提取类中的字段。。 val stu = new Student("张三",20)
    stu match {
          case Student(name,age)=>{
            println(s"name=${name},age=${age}")
    } }
    } }
    

    toString方法

    方便查看样例类成员

    equals方法

    可以直接用==比较两个样例类是否相等,既所有的成员变量是否相等

    hashCode方法

    如果所有成员变量值相同,则hash值相同,只要有一个不一样,则hash值不一样.

    copy方法

    可以快速的创建一个相同的实力对象.可以使用带名参数指定给成员进行重新赋值

    创建名字年龄分别为"李四", 21的对象
    通过copy拷贝,名字为"王五"的对象
    **示例**
    
    - 创建名字年龄分别为"李四", 21的对象
    - 通过copy拷贝,名字为"王五"的对象
    

    2. 样例对象

    跟java的枚举是一样的用法.
    只要一个类名有意义.不需要属性跟方法

    case object 样例对象名
    object Demo2CaseObject {
    3. 模式匹配
    java中的模式匹配是switch case,如果外界变量命中的一个case,如果不主动break,则会继续匹配下一个
    case
    scala中的模式匹配是 match case,如果外界变量命中的一个case,会自动break出去。 java只支持等值匹配,scala的模式匹配支持很多灵活的业务场景
    语法
    需求案例
     变量 match {
    case "常量1" => 表达式1 case "常量2" => 表达式2 case "常量3" => 表达式3 case _ => 表达式4
    }
    // 默认配
    object Dog{
        val name="wangcai"
        def say()=println("wangwang")
    } //去掉属性和方法,就是样例对象 case object Dog2
    //创建一个Trait,表示性别Sex枚举,
    trait Sex //定义它的两个实例,样例对象(男性——Male、女性——Female) case object Male extends Sex //定义一个Person样例类,它有两个成员(姓名、性别)
      case object Female extends Sex
      case class Person(name:String,sex:Sex)
      def main(args: Array[String]): Unit = {
    //创建两个Person对象("张三"、男性)、("李四"、"女") val p1 = Person("张三",Male)
    val p2 = Person("李四",Female)
    println(p1,p2)
    } }
    

    3. 模式匹配

    语法

    变量 match{
      case 类型1变量名: 类型1 => 表达式1 
      case _=> 表达式4
    }
    

    示例
    定义一个变量为Any类型,然后分别给其赋值为"hadoop"、1、1.0
    定义模式匹配,然后分别打印类型的名称

    val a:Any = "hadoop"
    val result = a match {
            case _:String => "String"
            case _:String => "String"
    }
    println(result)
    

    守卫

    就是java中case方法里的default,也就是说在没有匹配到值得情况下得取一个默认的值

    val a = StdIn.readInt()
    
    a match {
        case _ if a >= 0 && a <= 3 => println("[0-3]")
        case _ if a >= 4 && a <= 8 => println("[3-8]")
        case _ => println("未匹配")
    }
    

    匹配样例类

    scala可以使用模式匹配来匹配样例类,从而可以快速获取样例类的对象中的成员数据
    声明变量中的模式匹配:在一行代码中快速的定义多个变量,并且给他们赋值。

    obj match { //一举2得,匹配了类型,也获取了各个属性值
    
    case Customer(name,age)=>
    { println(s"它是Customer类,且name=${name},age=${age}")
    } }
    

    4. Option类型

    使用Option类型,可以用来有效避免空引用(null)异常。也就是说,将来我们返回某些数据时,可以返回一个Option类型来替代。

    • Some(x):表示实际的值

    • None:表示没有值

    • 使用getOrElse方法,当值为None是可以指定一个默认值

      /**
        * 定义除法操作
        * @param a 参数1
        * @param b 参数2
        * @return Option包装Double类型
        */
      def dvi(a:Double, b:Double):Option[Double] = {
        if(b != 0) {
          Some(a / b)
        }
        else {
          None
        }
      }
    
      def main(args: Array[String]): Unit = {
        val result1 = dvi(1.0, 5)
    
        result1 match {
          case Some(x) => println(x)
          case None => println("除零异常")
        }
      } 
    
    def dvi(a:Double, b:Double) = {
        if(b != 0) {
            Some(a / b)
        }
        else {
            None
        }
    }
    
    def main(args: Array[String]): Unit = {
        val result = dvi(1, 0).getOrElse(0)
    
        println(result)
    }
    

    5. 偏函数

    偏函数可以提供了简洁的语法,可以简化函数的定义。配合集合的函数式编程,可以让代码更加优雅。

    • 偏函数被包在花括号内没有match的一组case语句是一个偏函数

    • 偏函数是PartialFunction[A, B]的一个实例

    • A代表输入参数类型

    • B代表返回结果类型

    // func1是一个输入参数为Int类型,返回值为String类型的偏函数
    val func1: PartialFunction[Int, String] = {
        case 1 => "一"
        case 2 => "二"
        case 3 => "三"
        case _ => "其他"
    }
    
    println(func1(2))
    

    示例说明

    • 定义一个列表,包含1-10的数字
    • 请将1-3的数字都转换为[1-3]
    • 请将4-8的数字都转换为[4-8]
    • 将其他的数字转换为(8-*]
    val list = (1 to 10).toList
    
    val list2 = list.map{
        case x if x >= 1 && x <= 3 => "[1-3]"
        case x if x >= 4 && x <= 8 => "[4-8]"
        case x if x > 8 => "(8-*]"
    }
    
    println(list2)
    

    6.正则表达式

    Regex类

    • scala中提供了Regex类来定义正则表达式

    • 要构造一个RegEx对象,直接使用String类的r方法即可

    • 建议使用三个双引号来表示正则表达式,不然就得对正则中的反斜杠来进行转义

    val regEx = """正则表达式""".r
    

    findAllMatchIn方法

    • 使用findAllMatchIn方法可以获取到所有正则匹配到的字符串
    val r = """.+@.+\..+""".r
    
    val eml1 = "qq12344@163.com"
    val eml2 = "qq12344@.com"
    
    if(r.findAllMatchIn(eml1).size > 0) {
        println(eml1 + "邮箱合法")
    }
    else {
        println(eml1 + "邮箱不合法")
    }
    
    if(r.findAllMatchIn(eml2).size > 0) {
        println(eml2 + "邮箱合法")
    }
    else {
        println(eml2 + "邮箱不合法")
    }
    

    7. 异常处理

    def main(args: Array[String]): Unit = {
       val i = 10 / 0
        
        println("你好!")
      }
    
    Exception in thread "main" java.lang.ArithmeticException: / by zero
        at ForDemo$.main(ForDemo.scala:3)
        at ForDemo.main(ForDemo.scala)
    
    try {
        // 代码
    }
    catch {
        case ex:异常类型1 => // 代码
        case ex:异常类型2 => // 代码
    }
    finally {
        // 代码
    }
    
    • try中的代码是我们编写的业务处理代码
    • 在catch中表示当出现某个异常时,需要执行的代码
    • 在finally中,是不管是否出现异常都会执行的代码
    try {
        val i = 10 / 0
    
        println("你好!")
    } catch {
        case ex: Exception => println(ex.getMessage)
    } 
    

    抛出异常

     def main(args: Array[String]): Unit = {
       throw new Exception("这是一个异常")
     }
    
    Exception in thread "main" java.lang.Exception: 这是一个异常
       at ForDemo$.main(ForDemo.scala:3)
       at ForDemo.main(ForDemo.scala)
    

    8. 提取器(Extractor)

    之前我们学习过了,实现一个类的伴生对象中的apply方法,可以用类名来快速构建一个对象。伴生对象中,还有一个unapply方法。与apply相反,unapply是将该类的对象,拆解为一个个的元素。
    示例说明

    • 创建一个Student类,包含姓名年龄两个字段
    • 实现一个类的解构器,并使用match表达式进行模式匹配,提取类中的字段。
    
    object Student {
        def apply(name:String, age:Int) = {
            new Student(name, age)
        }
    
        def unapply(student:Student) = {
            val tuple = (student.name, student.age)
    
            Some(tuple)
        }
    }
    
    def main(args: Array[String]): Unit = {
        val zhangsan = Student("张三", 20)
    
        zhangsan match {
            case Student(name, age) => println(s"${name} => ${age}")
        }
    }
    

    9. 泛型

    scala和Java一样,类和特质、方法都可以支持泛型。我们在学习集合的时候,一般都会涉及到泛型。

    scala> val list1:List[String] = List("1", "2", "3")
    list1: List[String] = List(1, 2, 3)
    

    语法

    def 方法名[泛型名称](..) = {
        //...
    }
    

    不考虑泛型

    ef getMiddle(arr:Array[Int]) = arr(arr.length / 2)
    
      def main(args: Array[String]): Unit = {
        val arr1 = Array(1,2,3,4,5)
    
        println(getMiddle(arr1))
      }
    
    

    加入泛型之后

    def getMiddleElement[T](array:Array[T]) =
    array(array.length / 2)
    
    def main(args: Array[String]): Unit = {
        println(getMiddleElement(Array(1, 2, 3, 4, 5)))
        println(getMiddleElement(Array("a", "b", "c", "d", "e")))
    }
    

    泛型类

    scala的类也可以定义泛型。接下来,我们来学习如何定义scala的泛型类

    语法

    class 类[T](val 变量名: T)
    

    示例说明

    • 实现一个Pair泛型类
    • Pair类包含两个字段,而且两个字段的类型不固定
    • 创建不同类型泛型类对象,并打印
    case class Pair[T](var a:T, var b:T)
    
    def main(args: Array[String]): Unit = {
        val pairList = List(
            Pair("Hadoop", "Storm"),
            Pair("Hadoop", 2008),
            Pair(1.0, 2.0),
            Pair("Hadoop", Some(1.9))
        )
    
        println(pairList)
    }
    

    泛型的上下界

    def main(args: Array[String]): Unit = {
        demo(Array(new Person))
        demo(Array(new Policeman))
        // 编译出错:Superman是Policeman的子类
        // demo(Array(new Superman))
    }
    

    协变、逆变、非变 (掌握)

    class Pair[T]
    
    object Pair {
      def main(args: Array[String]): Unit = {
        val p1 = Pair("hello")
        // 编译报错,无法将p1转换为p2
        val p2:Pair[AnyRef] = p1
    
        println(p2)
      }
    }
    

    示例

    • 定义一个Super类、以及一个Sub类继承自Super类
    • 使用协变、逆变、非变分别定义三个泛型类
    • 分别创建泛型类来演示协变、逆变、非变
    class Super
    class Sub extends Super
    
    class Temp1[T]
    class Temp2[+T]
    class Temp3[-T]
    
    def main(args: Array[String]): Unit = {
        val a:Temp1[Sub] = new Temp1[Sub]
        // 编译报错
        // 非变
        //val b:Temp1[Super] = a
    
        // 协变
        val c: Temp2[Sub] = new Temp2[Sub]
        val d: Temp2[Super] = c
    
        // 逆变
        val e: Temp3[Super] = new Temp3[Super]
        val f: Temp3[Sub] = e
    }
    

    10. 隐式转换和隐式参数

    隐式转换

    • 隐式转换方法,可以让一个对象,转换成一个新对象,这个新对象拥有额外的我们定义的行为。

    • 隐式转换方法,需要定义一个方法,只接受一个变量,这个变量就是我们需要转换的那个对象,该方法用implicit关键字来修饰。

    • 隐式转换方法需要定义在object中 在需要用到隐式转换的地方,手动引入隐式

    • 转换(使用import) 编译器自动调用隐式转化后的方法

    import java.io.File
    object demoStudent {
    def main(args: Array[String]): Unit = { //5.main方法中,定义文件对象
      val file12 = new File("/Users/ttony/Desktop/back/deom/data/1.txt")
      //6.手动引入RichFile的file2RichFile方法 //import RichFile.file2RichFile(file:File)
      //如果在当前同一个作用域中有隐式转换方法,会自动导入隐式转换。
      implicit def file2RichFile(a: File) = new RichFile(file12)
      //7.在file上调用read()方法,打印结果
      //当对象调用类中不存在的方法或者成员时,编译器会自动将对象进行隐式转换
      println(file12.read())
      }
    }
    
    import java.io.File
    import scala.io.Source
    
    class RichFile (file: File){
      def read()=Source.fromFile(file).mkString
    }
    object RichFile{
      //4.伴生对象中定义一个方法file2RichFile,返回RichFile的一个对象实例,这个方法用implicit修饰。
      implicit def file2RichFile(file:File)=new RichFile(file)
    }
    

    隐式参数

    • 在一个柯里化方法,有多个参数列表,其中最后一个列表,可以做成隐式参数,这个参数需要用implicit关 键字来修饰

    • 在一个object中定义一个implicit修饰的默认的 隐式值(是成员属性),后期可以自动的被导入到上面定义 的隐式参数中

    • 和隐式转换一样,可以使用import手动导入2中的默认的隐式参数

    • 调用1中的柯里化方法时,可以不传入implicit修饰的参数列表,编译器会自动查找缺省值

    object demoStudent {
      ////1.定义一个柯里化方法quote(String)(Tuple),第二个参数用implicit修饰。
      // 可将传入的值,使用一个分隔符前缀、后缀包括起来
      def quot(str:String)(implicit del:(String,String)) ={
        del._1 + str + del._2
      }
      def main(args: Array[String]): Unit = {
        import DelimiterParam.DEFAULT_DELIMITER
        println(quot("你好"))
      }
    
    }
    
    // 定义一个object,包含一个成员变量,用implicit修饰,
    // 表示隐式参数,也是步骤1的潜在的分隔符
    object DelimiterParam {
      implicit  val DEFAULT_DELIMITER:(String,String) = ("<<<",">>>")
    }
    

    相关文章

      网友评论

          本文标题:Scala基础语法 二

          本文链接:https://www.haomeiwen.com/subject/sotqhltx.html