scala基础

介绍

Scalable Language

之所以说其是可伸缩的,是因为 scala 既体现了面向对象和函数式编程等不同语言范式,又融合了不同语言的新特性

The essence of Scala is the fusion of functional programming and object-oriented programming in a typed setting:

  • Functions for the logic
  • Objects for the modularity

As Martin Odersky has stated, “Scala was designed to show that a fusion of functional and object-oriented programming is possible and practical.”

官网https://www.scala-lang.org/

Scala 语言是基于Java开发的,所以其编译后的文件也是字节码文件,并可以运行在JVM中


变量

在scala中有两种类型的变量

  • val 创建一个不可变量(例如 final 在Java中)也就是常量,也可称为值value
  • var 创建一个可变变量
object Test {
    def main(args: Array[String]): Unit = {
        var s = "a"
        s = "b"
        
        val s1 = "a"
        s1 = "b" //会报错
    }
}

变量的类型如果能够通过变量值推断出来,那么可以省略类型声明,这里的省略,并不是不声明,而是由Scala编译器在编译时自动声明

object ScalaVariable {
    def main(args: Array[String]): Unit = {
        // 因为变量值为字符串,又因为Scala是静态类型语言,所以即使不声明类型
        // Scala也能在编译时正确的判断出变量的类型,这体现了Scala语言的简洁特性。
        var username = "zhangsan"
        val userpswd = "000000" 
    }
}

Java语法中变量在使用前进行初始化就可以,但是Scala语法中是不允许的,必须显示进行初始化操作

与 Java含有基本类型不同,scala是完全面向对象的语言,所以不存在基本数据类型的概念,有的只是任意值对象类型(AnyVal)和任意引用对象类型(AnyRef)

Scala语言中没有三元运算符,不支持 a++ 语法,只能用a+=1


打印输出

字符串连接

object ScalaString {
    def main(args: Array[String]): Unit = {
        // 字符串连接
        println("Hello " + name)
    }
}

传值给字符串

object ScalaString {
    def main(args: Array[String]): Unit = {
        // 传值字符串(格式化字符串)
        printf("name=%s\n", name)
    }
}

插值字符串

object ScalaString {
    def main(args: Array[String]): Unit = {
        // 插值字符串
        // 将变量值插入到字符串
        println(s"name=${name}")
    }
}

多行字符串

object ScalaString {
    def main(args: Array[String]): Unit = {
        // 多行格式化字符串
        // 在封装JSON或SQL时比较常用
        // | 默认顶格符
        println(
                s"""
                      | Hello
                      | ${name}
       			 """.stripMargin)
	}
}

循环中断

scala是完全面向对象的语言,所以无法使用break,continue关键字这样的方式来中断,或继续循环逻辑,

而是采用了函数式编程的方式代替了循环语法中的break和continue

object ScalaLoop {
    def main(args: Array[String]): Unit = {
        scala.util.control.Breaks.breakable {
            for ( i <- 1 to 5 ) {
                if ( i == 3 ) {
                    scala.util.control.Breaks.break
                }
                println(i)
            }
        }
    }
}

函数式编程

scala编程语言将 函数式编程 和 面向对象编程 完美地融合在了一起

[修饰符] def 函数名 ( 参数列表 ) [:返回值类型] = {
    函数体
}

private def test( s : String ) : Unit = {
    println(s)
}

scala中存在方法和函数两个不同的概念,二者在语义上的区别很小

scala方法是类的一部分,而函数是一个对象,也可以说类中定义的函数即是方法

类中的方法有重载和重写的概念而函数没有,函数可以嵌套声明而方法不可以


可变参数

函数中可变参数的写法如下,可变参数不能放在参数列表的前面,一般放在最后

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        // Error
        //def fun77(names:String*, name:String): Unit = {
            
        //}
        def fun777( name:String, names:String* ): Unit = {
            println( name )
            println( names )
        }
    }
}

函数至简原则

所谓的至简原则,其实就是Scala的作者为了开发人员能够大幅度提高开发效率

通过编译器的动态判定功能,帮助我们将函数声明中能简化的地方全部都进行了简化,也就是说将函数声明中那些能省的地方全部都省掉

所以这里的至简原则,简单来说就是:能省则省


高阶函数编程

所谓的高阶函数,其实就是将函数当成一个类型来使用,而不是当成特定的语法结构


面向对象编程

单例对象

所谓的单例对象,就是在程序运行过程中,指定类的对象只能创建一个,而不能创建多个,这样的对象可以由特殊的设计方式获得,也可以由语言本身设计得到,比如 object 伴生对象,对应java中的静态类

Scala语言是完全面向对象的语言,所以并没有静态的操作,但是为了能够和Java语言交互,就产生了一种特殊的对象来模拟静态类对象,该对象为单例对象

若单例对象名与类名一致,则称该单例对象是这个类的伴生对象,这个类的所有 “静态” 内容都可以放置在它的伴生对象中声明,然后通过伴生对象名称直接调用

如果类名和伴生对象名称保持一致,那么这个类称之为伴生类。Scala编译器可以通过伴生对象的apply方法创建伴生类对象。apply方法可以重载,并传递参数,且可由Scala编译器自动识别。所以在使用时,其实是可以省略的


特质

Scala 将多个类的相同特征从类中剥离出来,形成一个独立的语法结构,称之为 “特质”(特征),对应java中的接口

Scala中没有 interface 关键字,而是采用特殊的关键字 trait 来声明特质,如果一个类符合某一个特征(特质),那么就可以将这个特征(特质)“混入”到类中

这种混入的操作可以在声明类时使用,也可以在创建类对象时动态使用


基本语法

trait 特质名称
class 类名 extends 父类(特质1) with 特质2 with特质3
trait Operator {

}
trait DB{

}
class MySQL extends Operator with DB{

}

动态混入

object ScalaTrait{
    def main(args: Array[String]): Unit = {
        val mysql = new MySQL with Operator
        mysql.insert()
    }
}
trait Operator {
    def insert(): Unit = {
        println("insert data...")
    }
}
class MySQL {

}

初始化叠加

object ScalaTrait{
    def main(args: Array[String]): Unit = {
        val mysql = new MySQL
    }
}
trait Operator {
    println("operator...")
}
trait DB {
    println("db...")
}
class MySQL extends DB with Operator{
    println("mysql...")
}

功能叠加

object ScalaTrait {
    def main(args: Array[String]): Unit = {
        val mysql: MySQL = new MySQL
        mysql.operData()
    }
}

trait Operate{
    def operData():Unit={
        println("操作数据。。")
    }
}
trait DB extends Operate{
    override def operData(): Unit = {
        print("向数据库中。。")
        super.operData()
    }
}
trait Log extends Operate{

    override def operData(): Unit = {
        super.operData()
    }
}
class MySQL extends DB with Log {

}

集合

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

对于几乎所有的集合类,Scala都同时提供了可变(scala.collection.mutable)和 不可变的版本(scala.collection.immutable

这里的可变是指可以在适当的地方被更新或扩展,这意味着你可以修改,添加,移除一个集合的元素

而不可变集合类,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变,所以这里的不可变并不是变量本身的值不可变,而是变量指向的那个内存地址不可变


数组

  • 不可变数组 :Array

  • 可变数组 :scala.collection.mutable.ArrayBuffer

  • 可变数组和不可变数组转换

    import scala.collection.mutable
    import scala.collection.mutable.ArrayBuffer
    object ScalaCollection{
        def main(args: Array[String]): Unit = {
            val buffer = ArrayBuffer(1,2,3,4)
            val array = Array(4,5,6,7)
    
            // 将不可变数组转换为可变数组
            val buffer1: mutable.Buffer[Int] = array.toBuffer
            // 将可变数组转换为不可变数组
            val array1: Array[Int] = buffer.toArray
        }
    }
    

Seq集合

  • 不可变List :List

  • 可变List :scala.collection.mutable.ListBuffer

  • 可变集合和不可变集合转换

    import scala.collection.mutable
    import scala.collection.mutable.ListBuffer
    object ScalaCollection{
        def main(args: Array[String]): Unit = {
    
            val buffer = ListBuffer(1,2,3,4)
            val list = List(5,6,7,8)
     
            // 可变集合转变为不可变集合
            val list1: List[Int] = buffer.toList
            // 不可变集合转变为可变集合
            val buffer1: mutable.Buffer[Int] = list.toBuffer
        }
    }
    

Set集合

  • 不可变Set :Set
  • 可变Set :import scala.collection.mutable.Set

Map集合

  • 不可变Map :Map
  • 可变Map :scala.collection.mutable.Map

元组

在Scala语言中,我们可以将多个无关的数据元素封装为一个整体,这个整体我们称之为:元素组合,简称元组

队列

Scala也提供了队列(Queue)的数据结构 scala.collection.mutable.Queue,队列的特点就是先进先出。进队和出队的方法分别为 enqueuedequeue

并行

Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算

object ScalaCollection{
    def main(args: Array[String]): Unit = {
        val result1 = (0 to 100).map{x => Thread.currentThread.getName}
        val result2 = (0 to 100).par.map{x => Thread.currentThread.getName}

        println(result1)
        println(result2)
    }
}

模式匹配

Scala中的模式匹配类似于Java中的 switch 语法,但是scala从语法中补充了更多的功能,可以按照指定的规则对数据或对象进行匹配,所以更加强大

模式匹配语法中,采用 match 关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断

如果所有case都不匹配,那么会执行case _分支,类似于Java中default语句。如果不存在case _分支,那么会发生错误

object ScalaMatch{
    def main(args: Array[String]): Unit = {
        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)
    }
}

样例类

  • 样例类就是使用case关键字声明的类

  • 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如apply、unapply(即apply方法的逆过程,由对象到属性)、toString、equals、hashCode和copy

  • 样例类是为模式匹配而优化的类,因为其默认提供了unapply方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply方法

  • 构造器中的每一个参数都为val,除非它被显式地声明为var(不建议这样做)

case class User(name: String, var age: Int)

object ScalaCaseClass {
    def main(args: Array[String]): Unit = {
        val user: User = User("zhangsan", 11)
        val result = user match {
            case User("zhangsan", 11) => "yes"
            case _ => "no"
        }
        println(result)
    }
}

应用场景

变量声明

object ScalaMatch { 
    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 Person(name, age) = Person("zhangsan", 16)
        println(s"name=$name,age=$age")
    }
    case class Person(name: String, age: Int)
}

循环匹配

object ScalaMatch {
    def main(args: Array[String]): Unit = {
        val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
        for ((k, v) <- map) { //直接将map中的k-v遍历出来
            println(k + " -> " + v) //3个
        }
        println("----------------------")
        //遍历value=0的 k-v ,如果v不是0,过滤
        for ((k, 0) <- map) {
            println(k + " --> " + 0) // B->0
        }
        println("----------------------")
        //if v == 0 是一个过滤的条件
        for ((k, v) <- map if v >= 1) {
            println(k + " ---> " + v) // A->1 和 c->33
        }
    }
}

函数参数

object ScalaMatch {
    def main(args: Array[String]): Unit = {
        val list = List(
            ("a", 1), ("b", 2), ("c", 3)
        )
        val list1 = list.map {
            case ( k, v ) => {
                (k, v*2)
            }
        }
        println(list1)
    }
}

偏函数

所谓的偏函数,其实就是对集合中符合条件的数据进行处理的函数

偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查

List(1, 2, 3, 4, 5, 6, "test").collect { case x: Int => x + 1 }.foreach(println)

异常

Scala中的异常不区分所谓的 编译时异常和运行时异常,也无需显式抛出方法异常,所以Scala中没有throws关键字

object ScalaException {
    def main(args: Array[String]): Unit = {
        try {
            var n= 10 / 0
        } catch {
            case ex: ArithmeticException=>{
                // 发生算术异常
                println("发生算术异常")
            }
            case ex: Exception=>{
                // 对异常处理
                println("发生了异常1")
            }
        } finally {
            println("finally")
        }
    }
}

隐式转换

精度小的类型可以自动转换为精度大的类型,这个转换过程由编译器自动完成,这个转换操作我们称之为隐式转换

在其他的场合,隐式转换也起到了非常重要的作用。如Scala在程序编译错误时,可以通过隐式转换中类型转换机制尝试进行二次编译,将本身错误无法编译通过的代码通过类型转换后编译通过

慢慢地,这也形成了一种扩展功能的转换机制

隐式函数

object ScalaImplicit {
    def main(args: Array[String]): Unit = {
        implicit def transform( d : Double ): Int = {
            d.toInt
        }
        var d : Double = 2.0
        val i : Int = d
        println(i)
    }
}

隐式参数 & 隐式变量

object ScalaImplicit {
    def main(args: Array[String]): Unit = {
        def transform( implicit  d : Double ) = {
            d.toInt
        }
        implicit val dd : Double = 2.0
        println(transform)
    }
}

隐式类

隐式类非常强大,同样可以扩展类的功能,在集合的数据处理中,隐式类发挥了重要的作用

  • 其所带的构造参数有且只能有一个
  • 隐式类必须被定义在“类” 或 “伴生对象” 或 “包对象”里,即隐式类不能是顶级的
object ScalaImplicit {
    def main(args: Array[String]): Unit = {
        val emp = new Emp()
        emp.insertUser()
    }
    
    class Emp {
        
    }
    
    implicit class User( emp : Emp) {
        def insertUser(): Unit = {
            println("insert user...")
        }
    }
}

隐式机制

所谓的隐式机制,就是一旦出现编译错误时,编译器会从哪些地方查找对应的隐式转换规则,其实最直接的方式就是直接导入

  • 当前代码作用域
  • 当前代码上级作用域
  • 当前类所在的包对象
  • 当前类(对象)的父类(父类)或特质(父特质)

泛型

泛型不可变

object ScalaGeneric {
    def main(args: Array[String]): Unit = {

        val test1 : Test[User] = new Test[User] // OK
        val test2 : Test[User] = new Test[Parent] // Error
        val test3 : Test[User] = new Test[SubUser]  // Error

    }
    class Test[T] {
    }
    class Parent {
    }
    class User extends Parent{
    }
    class SubUser extends User {
    }
}

泛型协变

object ScalaGeneric {
    def main(args: Array[String]): Unit = {

        val test1 : Test[User] = new Test[User] // OK
        val test2 : Test[User] = new Test[Parent] // Error
        val test3 : Test[User] = new Test[SubUser]  // OK

    }
    class Test[+T] {
    }
    class Parent {
    }
    class User extends Parent{
    }
    class SubUser extends User {
    }
}

泛型逆变

object ScalaGeneric {
    def main(args: Array[String]): Unit = {

        val test1 : Test[User] = new Test[User] // OK
        val test2 : Test[User] = new Test[Parent] // OK
        val test3 : Test[User] = new Test[SubUser]  // Error

    }
    class Test[-T] {
    }
    class Parent {
    }
    class User extends Parent{
    }
    class SubUser extends User {
    }
}

泛型边界

泛型上限

object ScalaGeneric {
    def main(args: Array[String]): Unit = {
        val parent : Parent = new Parent()
        val user : User = new User()
        val subuser : SubUser = new SubUser()
        test[Parent](parent) // Error
        test[User](user)   // OK
        test[SubUser](subuser) // OK
    }
    def  test[A<:User]( a : A ): Unit = {
        println(a)
    }
    class Parent {
    }
    class User extends Parent{
    }
    class SubUser extends User {
    }
}

泛型下限

object ScalaGeneric {
    def main(args: Array[String]): Unit = {
        val parent : Parent = new Parent()
        val user : User = new User()
        val subuser : SubUser = new SubUser()
        test[Parent](parent) // OK
        test[User](user)   // OK
        test[SubUser](subuser) // Error
    }
    def  test[A>:User]( a : A ): Unit = {
        println(a)
    }
    class Parent {
    }
    class User extends Parent{
    }
    class SubUser extends User {
    }
}

正则表达式

object ScalaRegex {
    def main(args: Array[String]): Unit = {
        // 构建正则表达式
        val pattern = "Scala".r
        val str = "Scala is Scalable Language"

        // 匹配字符串 - 第一个
        println(pattern findFirstIn str)

        // 匹配字符串 - 所有
        val iterator: Regex.MatchIterator = pattern findAllIn str
        while ( iterator.hasNext ) {
            println(iterator.next())
        }

        println("***************************")
        // 匹配规则:大写,小写都可
        val pattern1 = new Regex("(S|s)cala")
        val str1 = "Scala is scalable Language"
        println((pattern1 findAllIn str1).mkString(","))
    }
}
posted @ 2022-11-17 20:12  黄一洋  阅读(10)  评论(0)    收藏  举报