菜单

Administrator
发布于 2026-05-18 / 1 阅读
0
0

Scala简洁入门小结

Scala简洁入门小结

介绍

Scala是一门现代的多范式语言,志在以简洁、优雅及类型安全的方式来表达常用的编程模型。它平滑地集成了面向对象和函数式语言的特性。

推荐阅读:Scala 2 的官方中文文档

本文可以分为三部分:

  1. 基本语法
  2. Scala面向对象
  3. Scala容器

基本语法

速览

首先来看一段简单的 Scala 程序,如果有Java 以及 Python 基础的话,那么这一段代码将会非常容易理解:

// 使用 object 定义一个单实例,类似于 class 关键字,但是有区别,后文中会提到
object example_summary {

  // 定义了一个方法,这个方法需要两个参数 x 以及 y,两个参数都是 Int 类型
  // 方法的返回值也是 Int 类型对象
  def multiply(x:Int,y:Int):Int={
    // 方法体中的最后一个表达式就是方法的返回值
    x * y
    // Scala 中也有一个 return 关键字,但是很少用
    // return x * y
  }

  // 使用 class 关键字创造一个普通类,后面跟着它的名字和构造参数
  // 主构造函数,也可以自定义辅助构造函数,后文中会提到
  class Greeter(prefix:String, suffix:String){
    // 方法 out 返回类型是 Unit,类似于 void
    def out(name:String): Unit ={
      println(prefix + name + suffix)
    }
  }

  // Main 函数,程序的入口
  // 类似于 Java 的 Main 函数需要一个 String[] args
  // Scala 也需要一个字符串列表 Array 是数组关键字
  def main(args:Array[String]):Unit={
    val x: Int = 1+4;                  // 定义 x 为整形类型,val 是常量,赋值之后不能在变化
    var s: String = "first val";       // var 是变量,赋值之后可以再变化
    var t = "first var";              // Scala 具有类型推断的能力,故而可以不指定类型来声明
    println(s)                        // first val
    println(t)                        // first var

    println(s.indexOf('v'))           // 6

    println({                         // 代码块中最后一个表达式的结果是代码块的计算结果
      val x = 1 + 1                   // 代码块中定义的变量属于局部变量
      x + 1
    })                               // 3

    println(x)                       // 5

    println(multiply(11,11));        // 121 可以使用 ; 来结束一行,但是没必要

    var greeter = new Greeter("欢迎 ", " 光临")
    greeter.out("黄伟");             // 欢迎 黄伟 光临
  }
}

类型

在 Scala 中,所有的值都有类型。

  • Any 是所有类型的超类型,也称为顶级类型。它定义了一些通用的方法如 equalshashCodetoString
  • AnyVal 代表值类型。有9个预定义的非空的值类型分别是:DoubleFloatLongIntShortByteCharUnitBoolean
  • AnyRef 代表引用类型。所有非值类型都被定义为引用类型。在Scala中,每个用户自定义的类型都是 AnyRef 的子类型。

类型转换

值类型可以按照下面的方向进行转换:

// 允许的转换方向
val x: Long = 987654321
val y: Float = x  // 9.8765434E8 (note that some precision is lost in this case)

val face: Char = '☺'
val number: Int = face  // 9786

// 不允许的转换方向
val x: Long = 987654321
val y: Float = x  // 9.8765434E8
val z: Long = y  // Does not conform

Scala循环

Scala 提供了三种循环方法,分别是 while 循环, do-while 循环以及 for 循环:

object test {
  def main(args:Array[String]): Unit ={
    // while 循环
    var a = 0
    while(a<10){
      print(a)
      a+=1
    }

    // do-while 循环
    var b = 0
    do{
      print(b)
      b+=1
    }while(b<10)

    // for 循环,从 0 到 10,右为开区间 until
    for(c <- 0 until 10){
      print(c)
    }
    // for 循环,从 0 到 10,右为闭区间 to
    for(d<-0 to 10){
      print(d)
    }

    // Scala 的 break 语法,有点特殊
    val loopBreaker = new Breaks;
    loopBreaker.breakable{
      for(e <- 0 to 10){
        print(e)
        loopBreaker.break()
      }
    }
  }
}

Scala异常处理

Scala 的异常处理和其它语言比如 Java 类似。Scala 抛出异常的方法和 Java一样,使用 throw 方法:

throw new RuntimeException()

Scala中的异常处理借鉴了模式匹配的思想:

object test {
  def main(args:Array[String]): Unit ={
    try {
      // 读取文件
      val f = new FileReader("input.txt")
    } catch {
      // 捕获异常 FileNotFoundException
      case ex: FileNotFoundException =>{
        println("Missing file exception")
      }
      // 捕获异常 IOException
      case ex: IOException => {
        println("IO Exception")
      }
      // 捕获异常 RuntimeException
      case ex: RuntimeException=>{
        println("RuntimeException")
      }
    }finally {
      println("Finish!")
    }
  }
}

Scala访问修饰符

Scala的访问修饰符有三种,分别是:privateprotected 以及 public。在默认情况下,Scala的访问级别都是 public

和Java 略有区别的是:

  1. private 不允许外部类访问内部类的私有成员
  2. protected 不允许同一个包下非子类访问

作用域保护

Scala中,访问修饰符可以通过使用限定词强调,格式为:

private[x] 
protected[x]

这里的x指代某个所属的包、类或单例对象。如 private[x] 表示这个成员除了对x中的类、包中类或者伴生对象可见外,对其他所有类都是 private

Scala面向对象

下面是一个定义类的例子:

// 使用 class 来定义 Person 类
// 拥有一个主构造函数,参数为 name, age 以及 company
// 构造函数中的参数如果使用 var 或者 val 修饰,则将会是类的成员变量
// 否则只能被当做一个类内不可变参数使用,不能被当做类的字段,外部也不能访问该变量
class Person(var name:String, var age:Int, var company:String){

  // 定义一个成员变量 hobby 类型为字符串
  var hobby:String = ""

  // 定义一个辅助构造函数,辅助构造函数中的第一个语句必须是调用主构造函数
  def this(name:String, age:Int)={
    this(name,age,"")
  }

  // 定义一个成员方法,接收一个字符串参数 newHobby,将成员变量 hobby 设置为 newHobby
  def addHobby(newHobby:String): Unit ={
    this.hobby = newHobby
  }

  // 重写父类 Any 的 toString方法
  override def toString(): String = {
    var result = "Person " + "Name: " + name
    if(company.isEmpty)result = result + " Unknown company"
    else result = result + " Company: " + company
    if(this.hobby.nonEmpty)result = result + " Hobby: " + this.hobby
    result
  }
}

object test {
  def main(args:Array[String]): Unit ={
    val hw = new Person("黄伟", 23, "XiaoMi")
    val p = new Person("小明",22)
    println(hw)             // Person Name: 黄伟 Company: XiaoMi
    println(p)              // Person Name: 小明 Unknown company
    hw.addHobby("看电影")
    println(hw)             // Person Name: 黄伟 Company: XiaoMi Hobby: 看电影
  }
}

私有成员

类中的成员默认是 public 的,可以使用 private 进行修饰:

class Person(name:String, var age:Int, var company:String){

  // 定义了私有变量 address_
  private var address_ = "Unknown"
  // 定义了私有变量 address_ 的 Getter 方法
  def address: String = address_
  // 定义了私有变量 address_ 的 Setter 方法
  def address_=(newAddress:String):Unit={
    this.address_ = newAddress
  }
  // 定义了私有方法 getAddress
  private def getAddress:String={
    s"Live in $address_"
  }

  override def toString: String = {
    s"Person Name: $name, Age: $age Company: $company Address: $getAddress"
  }
}

object test_map {
  def main(args:Array[String]): Unit ={
    val hw = new Person("黄伟", 23, "XiaoMi")
    val p = new Person("小明",25, "Xiaomi")
    hw.address="南京市建业区"
    println(hw)
    println(p)
  }
}

接口/特质

在Scala中使用特质 Trait 关键字来定义接口,使用 extends 来拓展接口,使用 override 来实现接口中定义的方法,使用关键字 with 来多继承接口:

// scala 中的特质,可以理解为接口
trait Drink{
  def drink(name:String): Unit
}

// scala 中的特质(接口)可以定义属性,也可以定义默认实现
trait Eat{
  def eat(name:String):Unit={
    println(s"I want to eat $name")
  }
}

// 第一个接口使用 extends,后续的接口使用关键字 with
class Person(name:String) extends Drink with Eat{
  override def drink(drinks: String): Unit = {
    println("the person " + name + " want to drink " + drinks)
  }

  override def eat(food:String):Unit={
    println("the person " + name + " want to eat " + food)
  }
}

object example {
  def main(args:Array[String]):Unit={
    val p = new Person("小明")
    p.drink("乌龙茶")    // the person 小明 want to drink 乌龙茶
    p.eat("炒饭")       // the person 小明 want to eat 炒饭
  }
}

抽象类与混合继承

Scala 如同 Java 一般也拥有抽象类,可以实现多个接口但是只能有一个父类:

// 抽象类
abstract class A {
  val message: String
}
// 实现了抽象类,并且改写了 message 属性
class B extends A {
  val message = "I'm an instance of class B"
}
// 接口拓展了抽象类 A ,并且增加了一个方法
trait C extends A {
  def loudMessage(): String = message.toUpperCase()
}
// 类 D 继承了类 B 和接口 C
class D(val name:String) extends B with C{
  println(s"Create a instance $name of class D")
}

object example_mixIn {
  def main(args:Array[String]): Unit ={
    val d = new D("Data")         // Create a instance Data of class D
    println(d.loudMessage())      // I'M AN INSTANCE OF CLASS B
  }
}

Scala容器

Scala数组

// 定义一个长度为 3 的数组,元素类型为字符串
var z = new Array[String](3)
// 也可以直接使用这种方式初始化一个数组
var z = Array("aaa", "bbb", "ccc")

循环遍历数组:

object test {
  def main(args:Array[String]): Unit ={
    var array = new Array[Int](10)

    for(i<-0 until 10)
      array(i) = i

    for(i<-0 until 10)
      println(array(i))
  }
}

函数式编程

函数式编程常用的几个方法是 filter,sortBy,map以及foreach:

object test {
  def main(args:Array[String]): Unit ={
    var array = Array("test", "Xiaomi", "xiaoming", "aaa", "ccc")
    array
      .filter(item => item.length > 3)
      .sortBy(item => item.length)
      .map(item => item + " Length: " + item.length)
      .foreach(println)

    // test Length: 4
    // Xiaomi Length: 6
    // xiaoming Length: 8
  }
}

Scala集合-列表

object test_map {
  def main(args:Array[String]): Unit ={
    val list = List("111", "222", "test", "XiaoMi")
    val temp = List("other", "new")

    println(list(1))                 // 按照索引获取列表元素  222
    println(list.tail)               // 获取除第一个元素之外的列表  List(222, test, XiaoMi)
    println(list.head)               // 获取列表中首个元素 111
    println(list.concat(temp))       // 拼接两个列表
    println(List.fill(5)(0))         // 通过填充新建一个长度为 5 元素为 0 的数组
    println(list.mkString(" = "))    // 111 = 222 = test = XiaoMi
  }
}

Scala集合-Set

object test_map {
  def main(args:Array[String]): Unit ={
    var set1 = Set(1,2,3)
    val set2 = Set(4,6,7)

    set1 = set1 + 4
    println(set1.exists(_ % 2 == 0)) //true  判断集合 set1 中是否存在偶数
    println(set1.drop(1))            //Set(2,3,4)
    println(set1 & set2)             // 求集合的交集
    println(set1 &~ set2)            // 求集合的差集
  }
}

Scala集合-Map

object test {
  def main(args:Array[String]): Unit ={
    var a = Map("1"->"test", "2"->"xiaomi", "3"->"xiaoming", "4"->"good")
    a.foreachEntry((key, value) => println("Key: " + key + " Value: " + value))

    // 在字典中新增一个键值对
    a += ("5" -> "better")
    // 在字典中删除一个键
    a -= "1"

    a.keys
      .filter(item => a(item).length > 2)
      .map(item => "key: " + item + " Value: "+ a(item))
      .foreach(println)
  }
}

Scala中的Option

在Scala中,使用Option对象表示可能为空的对象,如果返回不为空,则返回Some子类,如果返回为空,则返回None子类。

object test {
  def matchOption(x:Option[String]):String={
    x match{
      case Some(s) => s
      case None => "invalid"
    }
  }

  def main(args:Array[String]): Unit ={
    var map = Map('a'->"aaa", 'b'->"bbb", 'c'->"ccc")
    var item = map.get('a')

    println(item)             // Some(aaa)
    println(item.get)         // aaa
    println(map.get('d'))     // None

    println(matchOption(item))             // aaa
    println(matchOption(map.get('d')))     // invalid
  }
}

评论