• scala


    Scala

    概述

    Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的 静态类型编程语言(静态语言需要提前编译的如:Java、c、c++等,动态语言如:js)。

    1. Scala是一门多范式的编程语言,Scala支持面向对象和函数式编程。(多范式,就是多种编程方 法的意思。有面向过程、面向对象、泛型、函数式四种程序设计方法。)
    2. Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有 的Java类库,实现两种语言的无缝对接。
    3. Scala单作为一门语言来看,非常的简洁高效。

    变量和数据结构

    注释

    Scala 注释使用和 Java 完全一样。

    单行注释://

    多行注释:/**/

    文档注释:/*

    ​ *

    ​ */

    变量和常量

    常量:用val声明 val 常量名 [:常量类型]=初始值

    变量:用var声明 var 变量名 [:变量类型]=初始值

    注意:

    1. 能用常量的地方不用变量
    2. 声明变量时,类型可以省略,编译器自动推导,即类型推导
    3. 类型确定后,就不能修改,说明 Scala 是强数据类型语言。
    4. 变量声明时,必须要有初始值
    5. 在声明/定义一个变量时,可以使用 var 或者 val 来修饰,var 修饰的变量可改变, val 修饰的变量不可改。
    6. var 修饰的对象引用可以改变,val 修饰的对象则不可改变,但对象的状态(值) 却是可以改变的。

    数据类型

    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,是所有数据类型的子类,主要用在一个函数没有明确返回值时使 用

    在这里插入图片描述

    整数类型

    在这里插入图片描述

    浮点类型

    在这里插入图片描述

    字符类型

    字符类型可以表示单个字符,字符类型是 Char。

    布尔类型

    布尔类型也叫 Boolean 类型,Booolean 类型数据只允许取值 true 和 false。Boolean 类型占 1 个字节。

    Unit 类型、Null 类型和 Nothing 类型

    在这里插入图片描述

    1. Unit 类型用来标识过程,也就是没有明确返回值的函数。
    2. Null 类只有一个实例对象,Null 类似于 Java 中的 null 引用。Null 可以赋值给任 意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)
    3. Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方 法不会正常返回,而且由于 Nothing 是其他任意类型的子类,他还能跟要求返回值的方法兼 容。
    类型转换

    自动转换(隐士转换):精度小的自动向精度大的转换

    强制类型转换:调用toXxx()方法

    运算符

    算术运算符

    在这里插入图片描述

    对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整 数部分而舍弃小数部分。

    对一个数取模 a%b,和 Java 的取模规则一样。

    关系运算符

    在这里插入图片描述

    ==与equals

    java: ==比较两个变量本身的值,即两个对象在内存中的首地址;equals 比较字符串中所包含的内容是否相同。

    scala:==更加类似于 Java 中的 equals

    逻辑运算符

    在这里插入图片描述

    赋值运算符

    在这里插入图片描述

    位运算符

    在这里插入图片描述

    流程控制

    分支控制

    if(条件表达式){
        执行代码块
    }[else if(条件表达式){
        执行代码块
    }][else{
        执行代码块
    }]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    object s03 {
      def main(args: Array[String]): Unit = {
        println("input age")
        var age=StdIn.readInt()
        if(age<18){
          println("童年")
        }else if(age>=18&&age<30){
          println("中年")
        }else{
          println("老年")
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Scala 中 if else 表达式其实是有返回值的,具体返回值取决于满足条件的 代码体的最后一行内容。

    val res:String=if(age<18){
                  "童年"
                }else if(age>=18&&age<30){
                  "中年"
                }else{
                  "老年"
                }
        println(res)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Scala 中返回值类型不一致,取它们共同的祖先类型。

    val res:Any=if(age<18){
                  "童年"
                }else if(age>=18&&age<30){
                  "中年"
                }else{
                  100
                }
        println(res)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    for循环

    Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for 循环的特性被称 为 for 推导式或 for 表达式。

    for(变量<-a to b by c){//[a,b] 步长为 c
        todo
    }
    
    • 1
    • 2
    • 3
    for(变量 <-a until b by c){//[a,b) 步长c
        todo
    }
    
    • 1
    • 2
    • 3
    循环守护

    循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环 体内部,为 false 则跳过,类似于 continue。

    for(变量 <-a to b if 关于变量的条件语句){
        todo
    }
    
    • 1
    • 2
    • 3
    循环返回值
    val res = for(i <- 1 to 10) yield i
    println(res)
    
    • 1
    • 2

    将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字。

    while与do…while

    与java相同

    函数式编程

    Scala 语言是一个完全面向对象编程语言。万物皆对象

    对象的本质:对数据和行为的一个封装

    Scala 语言是一个完全函数式编程语言。万物皆函数。

    函数的本质:函数可以当做一个值进行传递

    在这里插入图片描述

    函数和方法的区别

    方法有访问权限,函数没有访问权限

    为完成某一功能的程序语句的集合,称为函数。

    类中的函数称之方法。

    函数没有重载和重写的概念;方法可以进行重载和重写

    Scala 中函数可以嵌套定义

    函数至简原则

    函数至简原则:能省则省

    1. return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
    2. 如果函数体只有一行代码,可以省略花括号
    3. 返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)。如果有 return,则不能省略返回值类型,必须指定
    4. 如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
    5. Scala 如果期望是无返回值类型,可以省略等号
    6. 如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
    7. 如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
    8. 如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略

    高级函数

    1. 函数可以作为值进行传递
    2. 函数可以作为参数进行传递
    3. 函数可以作为函数返回值返回
    匿名函数

    没有名字的函数就是匿名函数。

    (x:Int)=>{函数体}

    x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑

    传递匿名函数至简原则:

    1. 参数的类型可以省略,会根据形参进行自动的推导
    2. 类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参 数超过 1 的永远不能省略圆括号。
    3. 匿名函数如果只有一行,则大括号也可以省略
    4. 如果参数只出现一次,则参数省略且后面参数可以用_代替
    闭包

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

    object TestFunction {
     def main(args: Array[String]): Unit = {
     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()(b:Int)={
     a + b
     }
     println(f3()(3))
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    函数柯里化

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

    惰性加载

    当函数被调用是先执行被调函数里的语句。

    当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函 数才会执行。这种函数我们称之为惰性函数。

    def main(args: Array[String]): Unit = {
     lazy val res = sum(10, 30)
     println("----------------")
     println("res=" + res)//只有res调用sum函数才执行
    }
    def sum(n1: Int, n2: Int): Int = {
     println("sum 被执行。。。")//只有res调用该语句才输出
     return n1 + n2
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    azy 不能修饰 var 类型的变量

    面向对象

    [修饰符]class 类名{
        类体
    }
    
    • 1
    • 2
    • 3

    Scala 语法中,类并不声明为 public,所有这些类都具有公有可见性(即默认就是 public)

    一个scala源文件可以包含多个类

    创建对象

    val | var 对象名[:类型]=new 类型()
    
    • 1

    val 修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。

    var 修饰对象,可以修改对象的引用和修改对象的属性值

    自动推导变量类型不能多态,所以多态需要显示声明

    构造器

    Scala 类的构造器包括:主构造器和辅助构造器

    class 类名(形参列表){//主构造器
        def this(形参列表){//辅助构造器
            
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型 来区分。

    辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。

    构造器调用其他另外的构造器,要求被调用构造器必须提前声明。

    构造器参数

    Scala 类的主构造器函数的形参包括三种类型:未用任何修饰、var 修饰、val 修饰

    1. 未用任何修饰符修饰,这个参数就是一个局部变量 。
    2. var 修饰参数,作为类的成员属性使用,可以修改 。
    3. val 修饰参数,作为类只读属性使用,不能修改

    继承

    class Person(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 
    Person(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,1001)
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    特质

    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 采用了特质叠加的策略。

    所谓的特质叠加,就是将混入的多个 trait 中的冲突方法叠加起来

    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()
     }
    }
    object TestTrait {
     def main(args: Array[String]): Unit = {
     println(new MyBall().describe())
     }
    }
    //结果:my ball is a blue-foot-ball
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    特质叠加执行顺序

    上述案例中的 super.describe()调用的是父 trait 中的方法吗?

    案例中的 super,不是表示其父特质对象,而是表示上述叠加顺序中的下一个特质, 即,MyClass 中的 super 指代 Color,Color 中的 super 指代 Category,Category 中的 super 指代 Ball。

    如果想要调用某个指定的混入特质中的方法,可以增加约束:super[],例如 super[Category].describe()。

  • 相关阅读:
    Android 10.0 展讯工厂测试模式USB调试开关的分析
    docker简介和安装
    HTTP相关知识
    2022年12月编程语言排行榜公布!
    Docker consul
    【区块链技术与应用】(三)
    ​Linux·i2c驱动架构​
    Open3D 网格滤波
    Android JobScheduler介绍
    GP规范--STORE DATA
  • 原文地址:https://blog.csdn.net/weixin_57025392/article/details/127923054