Scala快速入门+示例

目录

快速上手使用版


定义和描述

基于JVM的语言,支持面向对象、面向函数,支持JVM和JavaScript
官网

Spark基于scala进行开发,Flink也提供了关于scala相应的API

idea

idea可能无法正常添加scala的框架(添加框架支持这个方法确实不行)

此处提供另一种办法

先安装scala插件

项目结构---->>库---->>添加scala的sdk

基础

关键字

关键字 描述 示例
package 定义一个包 package com.example.myapp
import 导入其他包或对象中的成员 import scala.collection.mutable.ListBuffer
class 定义一个类 class Person(val name: String, val age: Int)
object 定义一个单例对象 object MainApp extends App { println("Hello, World!") }
trait 定义一个特质 trait Logger { def log(msg: String): Unit }
extends 用于类的继承 class Student(name: String, age: Int) extends Person(name, age)
with 用于混入特质或多个特质 class Admin extends Person("Admin", 0) with Logger
type 定义类型别名或类型成员 type Name = String
for 用于循环和推导式 for (i <- 1 to 5) println(i)
private 定义一个私有成员 class MyClass { private val secret = "secret" }
protected 定义一个受保护成员 class Parent { protected val protectedVal = 1 }
abstract 定义一个抽象类或抽象方法 abstract class Animal { def makeSound: Unit }
sealed 限定类的继承 sealed trait Shape
final 禁止类或方法被重写或继承 final class Constants { val Pi = 3.14 }
implicit 定义一个隐式值或隐式转换 implicit val defaultTimeout: Int = 5000
lazy 定义一个惰性变量 lazy val lazyVal = { println("Computing..."); 42 }
override 重写父类或特质中的方法 class Dog extends Animal { override def makeSound = println("Woof") }
try 捕获异常的代码块 try { val x = 1 / 0 } catch { case _: ArithmeticException => println("Division by zero!") }
catch 捕获异常并处理 同上
finally 无论是否发生异常,都会执行的代码块 try { ... } finally { println("Cleanup!") }
throw 抛出一个异常 throw new IllegalArgumentException("Invalid argument!")
if 条件语句 val x = if (a > b) a else b
else 与if语句结合使用,表示其他情况 同上
match 模式匹配语句 val msg = num match { case 1 => "One" case _ => "Other" }
case 在match语句中使用,表示一个匹配项 同上
do 与while结合使用,表示循环体 do { println("Looping...") } while (condition)
while 条件循环 while (condition) { println("Looping...") }
return 从方法中返回值 def add(a: Int, b: Int): Int = { return a + b }
yield 在推导式(如for-comprehension)中产生一个值 val squares = for (i <- 1 to 5) yield i * i
def 定义一个方法 def greet(name: String): String = s"Hello, $name!"
val 定义一个不可变变量 val x = 10
var 定义一个可变变量 var y = 20; y = 30
this 指向当前对象或类的实例 class MyClass { def printThis = println(this) }
super 指向父类或特质的实例 class Child extends Parent { def callParentMethod = super.parentMethod }
new 创建对象或类的实例 val person = new Person("John", 30)
true 布尔值真 val isTrue = true
false 布尔值假 val isFalse = false
null 表示空值或不存在的对象 val emptyString: String = null

变量、常量

变量、常量初始化时,必须定义其值

scala 复制代码
object VariableExample {
  def main(args: Array[String]): Unit = {
    // 定义不可变变量
    val name: String = "Alice"
    // 或者省略类型注解,因为编译器可以推断出它是String类型
    val age = 30

    // 打印变量的值
    println(s"Name: $name, Age: $age")

    // 定义可变变量
    var count: Int = 0

    // 修改可变变量的值
    count = count + 1

    // 打印修改后的值
    println(s"Count: $count")

    // 尝试修改不可变变量会导致编译错误
    // name = "Bob" // 这行代码会导致编译错误,因为name是不可变的
    // var a	//错误,必须定义值
  }
}

输出

java的System.out.println也可以,因为允许混编

scala 复制代码
object PrintExample {
  def main(args: Array[String]): Unit = {
    // 使用println打印,并自动换行
    println("Hello, World!")
    
    // 使用print打印,不换行
    print("Hello, ")
    print("Scala!")
    
    // 你也可以打印变量和表达式的值
    val name = "Alice"
    val age = 30
    println(s"Name: $name, Age: $age")  // 使用字符串插值
    
    // 打印数组或集合
    val numbers = Array(1, 2, 3, 4, 5)
    println(numbers.mkString(", "))  // 使用mkString方法将数组转换为字符串
  }
}

数据类型

数据类型 描述 示例
Byte 8位有符号补码整数。数值区间为 -128 到 127 val byteVal: Byte = 100
Short 16位有符号补码整数。数值区间为 -32768 到 32767 val shortVal: Short = 20000
Int 32位有符号补码整数。数值区间为 -2147483648 到 2147483647 val intVal: Int = -1000000
Long 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 val longVal: Long = 9223372036854775807L
Float 32位, IEEE 754 标准的单精度浮点数 val floatVal: Float = 3.14f
Double 64位 IEEE 754 标准的双精度浮点数 val doubleVal: Double = 3.141592653589793
Char 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF val charVal: Char = 'A'
Boolean true或false val booleanVal: Boolean = true
Unit 表示无值,和Java语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 def printHello(): Unit = println("Hello, World!")
String 字符序列 val stringVal: String = "Hello, Scala!"
Null null 或空引用(在Scala中应尽量避免使用null,更推荐使用Option类型来处理可能的空值) var nullableVal: String = null // 尽量避免这样做
Nothing Nothing类型在Scala的类层级的最底端;它是任何其他类型的子类型。通常用于表示从不正常终止的函数(如抛出异常的函数)。 def error(): Nothing = throw new Exception("An error occurred")
Any Any是所有其他类的超类 val anyVal: Any = "This can be any type"
AnyRef AnyRef类是Scala里所有引用类(reference class)的基类(相当于Java中的Object) val anyRefVal: AnyRef = new Object()
AnyVal AnyVal类是Scala里所有值类(如Int, Double等)的基类(注意:AnyVal本身不是一个具体的类型,而是一个特性标记,用于优化值类型的处理) // AnyVal是一个抽象概念,不直接用于定义变量

注意

  1. 在Scala中,对于数值类型(如Byte, Short, Int, Long),当值超过其表示范围时,会发生类型溢出。
  2. 对于Float和Double类型的浮点数,由于精度限制,某些小数可能无法精确表示。
  3. 在Scala中,应尽量避免使用null值,因为null值可能导致运行时错误(如NullPointerException)。相反,Scala提供了Option类型来处理可能的空值情况。
  4. Nothing类型通常用于表示从不返回正常结果的函数(如总是抛出异常的函数)。在实际编程中,你很少需要直接声明Nothing类型的变量或返回值。
  5. Any和AnyRef是Scala类型系统的顶层类型。Any是所有类型的超类,包括值类型和引用类型;而AnyRef是所有引用类型的超类(不包括值类型)。

类型转换


显示类型转换

scala 复制代码
object ExplicitTypeConversion {
  def main(args: Array[String]): Unit = {
    // 将Double转换为Int,注意这可能会导致精度丢失
    val doubleValue: Double = 123.45
    val intValue: Int = doubleValue.toInt // 显式类型转换
    println(s"Double to Int: $intValue") // 输出: Double to Int: 123

    // 将String转换为Int
    val stringValue: String = "456"
    val intValueFromString: Int = stringValue.toInt // 这要求字符串内容是一个有效的整数
    println(s"String to Int: $intValueFromString") // 输出: String to Int: 456

    // 将Any类型转换为具体类型(假设你知道它的实际类型)
    val anyValue: Any = "789"
    val stringFromAny: String = anyValue.asInstanceOf[String] // 显式类型转换,要求实际类型匹配
    println(s"Any to String: $stringFromAny") // 输出: Any to String: 789
  }
}

隐式类型转换

scala 复制代码
object ImplicitTypeConversion {
  def main(args: Array[String]): Unit = {
    // 隐式地将Byte转换为Int
    val byteValue: Byte = 10
    val sum: Int = byteValue + 20 // 在这里,byteValue会被隐式地提升为Int类型
    println(s"Byte to Int (implicit): $sum") // 输出: Byte to Int (implicit): 30

    // 使用Scala的RichInt、RichDouble等隐式转换
    val intValue: Int = 10
    val bigIntValue: BigInt = intValue // RichInt提供了到BigInt的隐式转换
    println(s"Int to BigInt (implicit): $bigIntValue") // 输出: Int to BigInt (implicit): 10
  }
}

函数式编程

函数和方法的区别

  1. Scala 中存在方法与函数两个不同的概念,二者在语义上的区别很小。scala 方法是类的一部分 ,而函数是一个对象 ,可以赋值给一个变量,也可以作为方法或其它函数的参数。换句话来说在类中定义的即是方法。scala 中的方法跟 Java 的类似,方法是组成类的一部分。scala 中的函数则是一个完整的对象。

  2. Scala中的方法和函数从语法概念上来讲,一般不好区分,所以简单的理解就是:方法也是函数。只不过类中声明的函数称之为方法,其他场合声明的就是函数了。类中的方法是有重载和重写 的。而函数没有重载和重写的概念 ,但是函数可以嵌套声明使用,方法不行

特性 方法(Method) 函数(Function)
定义位置 类的一部分 独立的对象,可以赋值给变量,作为参数传递
语义区别 在类中定义的即是方法 在类外部或其他场合声明的称为函数
与Java的关系 与Java的方法类似 是Scala特有的完整对象
重载与重写 支持重载和重写 不支持重载和重写
嵌套声明 不能嵌套声明使用 可以嵌套声明使用

定义示例

有参+带返回值

冒号后面定义的是String表示返回一个String类型的值,如何返回则是在整个函数体的末尾

以下示例代码结果是"wunaiieq"而不是"hello world"

scala 复制代码
package com.wunaiieq


object Example {
  def main(args: Array[String]): Unit = {
    /**@param arg 定义的参数,String类型
     * @return 冒号后面定义的是String表示返回一个String类型的值,如何返回则是在整个函数体的末尾
     * */
    def f1(arg: String): String = {
      arg + " world"
      "wunaiieq"
    }
    println(f1("hello"))
  }
}
有参+没有返回值
scala 复制代码
package com.wunaiieq


object VariableExample {
  def main(args: Array[String]): Unit = {
    /**@param arg 定义的参数,String类型
     * @return 冒号后面定义的是Unit表示没有返回值
     * */
    def f1(arg: String): Unit = {
      arg + " world"
      "wunaiieq"
    }
  }
}

注意点

  1. 函数定义语法 用def来定义

  2. 可以定义传入的参数,要指定传入参数的类型

  3. 函数可以写返回值的类型也可以不写,会自动推断,有时候不能省略,必须写,比如在递归函数中或者函数的返回值是函数类型的时候。

scala 复制代码
def funcD3(name:String,score:Double){
  //....
  //return s"有参数有返回值,Hello ${name},your score is ${score}"
  s"有参数有返回值,Hello ${name},your score is ${score}"
}
println(funcD3("diaosi",100))
输出结果为:()
  1. scala中函数有返回值时,可以写return,也可以不写return,会把函数中最后一行当做结果返回。当写return时,必须要写函数的返回值。

  2. 如果函数体可以一行搞定,可以将函数定义时的{}省略不写

  3. 传递给函数的参数可以在函数中使用,并且scala规定函数的传过来的参数为val的,不是var的。

  4. 如果去掉函数体前面的等号,那么这个方法返回类型必定是Unit的。这种说法无论方法体里面什么逻辑都成立,scala可以把任意类型转换为Unit.假设,里面的逻辑最后返回了一个String,那么这个返回值会被转换成Unit,并且值会被丢弃。

面向对象

object和class的区别

特性 object class
实例化 单例,只能有一个实例 可以有多个实例
实例创建 实例在对象定义时自动创建,不能通过new关键字实例化 使用new关键字来实例化
继承 不能被继承 可以被其他类继承
构造函数 没有构造函数的概念 可以有构造函数,用于初始化实例
用途 通常用于定义包含main方法的单例对象,作为程序的入口点 用于定义可以实例化的类型,具有状态和行为
示例 object MySingleton { ... } class MyClass { ... }

对象的属性

属性类型 描述 权限修饰符 访问级别
val 不可变属性,一旦赋值后不能改变 private 仅类内部可见
protected 类及其子类可见
public 所有地方可见(默认)
var 可变属性,可以在赋值后改变 private 仅类内部可见
protected 类及其子类可见
public 所有地方可见(默认)
隐式属性(通过getter/setter) 通过方法定义的属性,Scala鼓励使用这种方式进行属性封装 private[包名] 仅在指定包内可见
protected[包名] 在指定包内的类及其子类可见
无修饰符(默认public) 所有地方可见

注意:

  1. 在Scala中,val用于定义不可变属性,而var用于定义可变属性。
  2. 默认情况下,Scala的属性是public的,但可以通过添加适当的访问修饰符来限制其访问级别。注意,Scala中没有public关键字
  3. Scala还提供了包级别的访问修饰符,如private[包名]protected[包名],这些修饰符允许你更精细地控制属性的可见性。
  4. 隐式属性通常是通过getter和setter方法定义的,这是Scala中封装属性的推荐方式。尽管Scala没有显式的语法来定义这些方法,但你可以通过定义带有相同名称的def方法来隐式地创建它们。

示例
注意,Scala中没有public关键字

scala 复制代码
package com.wunaiieq

object AttributeAccessExample {
  // 定义一个类,包含不同访问权限的属性
  class Person(
                private val id: Int,         // 私有不可变属性
                private[this] var name: String, // 当前对象私有可变属性(注意:private[this]是Scala特有的,限制为当前对象私有)
                protected var age: Int,      // 受保护可变属性,子类可访问
                var email: String     // 公共可变属性
  ) {
    // 提供一个公共的getter方法来访问私有属性id
    def getId: Int = id

    // 提供一个公共的getter和setter方法来访问当前对象私有属性name
    def getName: String = name
    def setName(newName: String): Unit = {
      name = newName
    }

    // 由于age是受保护的,它可以在子类中被访问和修改
    // 这里我们不需要额外的getter和setter方法,除非我们想在类外部以某种方式限制访问

    // email已经是公共的,所以我们可以直接访问和修改它

    // 为了演示,我们添加一个方法,该方法会根据年龄打印一条消息
    def greet(): Unit = {
      println(s"Hello, my name is $name and I am $age years old. You can reach me at $email.")
    }
  }

  // 定义一个子类,继承自Person类
  class Employee(id: Int, name: String, age: Int, email: String, val jobId: String) extends Person(id, name, age, email) {
    // 由于age是受保护的,我们可以在这里访问它
    def promote(): Unit = {

      var newAge = age.+(1) // 假设晋升会增加年龄(这只是一个示例,实际情况可能不同)
      println(s"Employee $name has been promoted. New age: $newAge")
    }
  }

  // 主函数,用于演示如何创建Person和Employee对象,并访问它们的属性
  def main(args: Array[String]): Unit = {
    // 创建一个Person对象
    val person = new Person(1, "Alice", 30, "alice@example.com")
    // 由于id是私有的,我们需要通过getId方法来访问它
    println(s"Person ID: ${person.getId}")
    // 修改name和email属性
    person.setName("Alice Smith")
    person.email = "alice.smith@example.com"
    // 调用greet方法
    person.greet()

    // 创建一个Employee对象
    val employee = new Employee(2, "Bob", 25, "bob@example.com", "ENG001")
    // 调用promote方法,这将增加员工的年龄
    employee.promote()
    // 由于Employee继承自Person,我们可以调用greet方法
    employee.greet()

    // 注意:我们不能直接访问employee的private[this] name属性,因为它在当前Employee对象之外是不可见的
    // 同样,我们也不能直接访问person的受保护属性age,除非我们有一个Person类型的引用并且是在Person类或其子类的上下文中
  }
}
相关推荐
csbysj202028 分钟前
如何使用 XML Schema
开发语言
R6bandito_34 分钟前
STM32中printf的重定向详解
开发语言·经验分享·stm32·单片机·嵌入式硬件·mcu
earthzhang202141 分钟前
【1007】计算(a+b)×c的值
c语言·开发语言·数据结构·算法·青少年编程
杨枝甘露小码1 小时前
Python学习之基础篇
开发语言·python
间彧1 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧1 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧1 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧1 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧1 小时前
Spring Cloud Gateway详解与应用实战
后端
武文斌771 小时前
项目学习总结:LVGL图形参数动态变化、开发板的GDB调试、sqlite3移植、MQTT协议、心跳包
linux·开发语言·网络·arm开发·数据库·嵌入式硬件·学习