Scala
The name Scala comes from the word scalable, and true to that name, the Scala language is used to power busy websites and analyze huge data sets.
Scala特性:
-
高级语言:无需处理底层概念,如指针和内存管理;
-
面向对象和函数式编程:函数也能当成值来使用,定义匿名函数,支持高阶函数,允许嵌套多层函数;支持函数式和面向对象混合编程。
- Functions for the logic
- Objects for the modularity
-
静态类型(编译时检查),具有表达性强的类型系统(可自动推测类型,而无需为变量声明固定类型);
-
Scala源代码被编译成Java字节码运行在Java虚拟机上,可以无缝与现有的Java类库交互。
-
并发性:Scala使用Actor作为其并发模型,Actor是类似线程的实体,通过邮箱发收消息。
-
应用:服务、大数据应用、浏览器(Scala.js)。
安装
使用Coursier
使用系统软件仓库或安装包
不推荐:不能一次性安装所有工具。
Ubuntu (scala-2.11)
apt install scala # 包括scalac、scala、fsc、scaladoc
安装sbt
echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | sudo tee /etc/apt/sources.list.d/sbt.list
echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | sudo tee /etc/apt/sources.list.d/sbt_old.list
curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add
sudo apt update && sudo apt install sbt
Windows
winget install scala
winget install sbt
Scala程序
交互式编程
脚本
// class definition similar to JAVA
object ExampleClass { // object is singleton class
def main(args: Array[String]) {
println("Hello, world!") // 输出 Hello World
}
}
@main def main(args:Array[String]) = {...} // scala3
基本语法
语句可以用分号(;)结束或换行符。
包
package com.runoob // java package style
class HelloWorld
package com.runoob{ // c# Namespace style
class HelloWorld
}
导入依赖包:使用_
代表包中所有可导入内容。
import java.util.*
import org.apache.spark.sla._
import scala.jdk.CollectionConverters.*
val scalaList: Seq[Integer] = JavaClass.getJavaList().asScala.toSeq
流行的Scala库
- Play Framework:Web应用服务;
- Lagom:微服务架构;
- Apache Spark:分布式大数据处理。
- Scala.js:Web前端应用。
- 其他Scala应用。
数据类型
Scala与Java有着相同的数据类型,scala没有java中的原生类型。空值是 scala.Null 类型。
变量
变量声明
var myVar [: String] = "Foo" // 变量
val myVal [: String] = "Foo" // 常量
类型推断:根据初始化值推断变量类型,而无需指定变量类型。
类型转换
Int
和Long
不能自动类型转换(ClassCastException
),需要使用强制类型转换:
v.asInstanceOf[Type]
Any
类型只向其实际类型转换,不能直接转换为其他类型;必须还原实际类型后执行强制转换。
运算符
- 算术运算符:
+,-,*,/,%
- 比较运算符:
==,!=,>,<,>=,<=
- 逻辑运算符:
&&,||,!
- 位运算符:
&,|,^,~,<<,>>,>>>
(>>>
右移补零) - 赋值运算符:
=,+=,-=,...
类
Scala中的类不声明为public
,一个Scala源文件中可以有多个类。
class Point(xc: Int, yc: Int) extends baseclass(args) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) { }
}
所有类继承自Any
,其子类包括AnyVal
(值类型)和AnyRef
(引用类型,类似于Java)。
Traits
Traits(特征) 相当于Java的接口。与接口不同的是,它还可以定义属性和方法的实现。
使用
new
关键字创建对象。
数组(Array)
import Array._
var array:Array[String] = new Array[String](3)
var array = new Array[String](3)
var myMatrix = ofDim[Int](3,3) // 二维数组
var x = range(1,10,2) //start stop step Range
下标访问符为
()
,而非[]
。泛型类型声明符为
[]
,而非<>
(容器类型)。
容器(Collection)
不可变对象
Scala默认使用不可变对象(scala.collection.immutable
)。可以导入collection.mutable
包使用可变对象版本。
import scala.collection.mutable
var s = mutable.Set()
修改对象的操作返回新对象。
List
Nil
表示空列表。
Seq
是List继承的特征(trait)。
Set
set(val)
判断值是否在集合中。无法按下标返回元素。
Map
var A:Map[Char,Int] = Map()
A += ('I' -> 1) // add key-value
val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF")
println(colors("red"))
for (c <- colors){
println(c) // iterate c is (key,value) tuple
}
Tuple
使用
t._idx
访问元组的元素(idx 1-based
);目前 Scala 支持的元组最大长度为 22。
Option
Iterator
运算符
:
用于声明运算符与相邻对象的结合关系。
var a = List(1,2,3), c = List(4,5,6), item = 10
val b = a:+item // append a with item
val b = item+:a // prepend a with item: item::a
val b = a++c // appended c to a
val b = a++:c // prepend a to c: also a:::c
+
运算符用于字符串(String
)拼接。
:++
error.
Java容器
访问修饰符
方法和函数
Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。
方法定义语法
方法声明中,可以选择指定参数类型、参数默认值、返回值类型。
def sum(x: Int, y: Int = 0)[: Int]= x + y // expression style
@Transaction
@throws(classOf[IOException])
def methodName ([arg1:Int, arg2 Double])[: Double] = // method style
{
statements
return [expr]
}
def matchState(x): Int=x match{...} // methods with single match
公开方法需要声明返回类型,局部或私有方法可以省略返回类型声明(
: Int
)。无返回值,则声明
: Unit
(类似于void
)。类似于Java,可以声明标注(Annotations),包括抛出异常(Java使用关键字
throws
抛出异常)。
method style
与多数编程语言类似,使用{}
代码块表示函数体。
expression style
使用=
运算符连接单句表达式作为函数体(类似于Lambda表达式)。
match表达式
函数对象
函数对象保存一个匿名函数定义,=>
运算符用于分隔参数列表和函数体。
val f1 = (a: Int, b: Int) => a + b
val f2 = { (a: Int, b: Int) =>
val sum = a + b
sum // return sum
}
闭包
匿名函数及其引用的外部作用域中的对象组成闭包。
factor = 5
val multiplier = (i:Int) => i * factor
注意函数返回值使用
=
,方法返回值使用=>
。
Map and Reduce
传递(匿名)函数对象作为map
和reduce
的参数。
val l = List(2, 5, 3, 6, 4, 7)
val sum = l.reduce((x, y) => x+y)
val sqrt = l.map(x => x*x)
模式匹配(switch-case)
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many"
}
正则表达式
import scala.util.matching.Regex
流程控制
条件
y = x match {
case hd :: tail => hd + sum(tail)
case Nil => 0
}
循环
for ( x <- iterable ){
println(x)
}
异常处理
try {
val f = new FileReader("input.txt")
} catch {
case ex: FileNotFoundException =>{
println("Missing file exception")
}
case ex: IOException => {
println("IO Exception")
}
} finally {
println("Exiting finally...")
}
输入输出
Scala 进行文件写操作,直接用的都是 java中 的 I/O 类 (java.io.File)。
Java的标准输入输出已经导入运行环境,可以直接调用函数如print
、println
,无需添加包名(System.out
)。
Scala项目
sbt
是首选的Scala项目管理工具,其他工具包括ant
、gradle
、maven
……
sbt项目
创建项目
sbt new scala/hello-world.g8 # Scala 3 project
sbt new scala/scala3.g8 # Scala 2 project
需要下载运行环境(包括从Maven仓库下载依赖库,视网络环境可能占用一定时间)。
项目结构
project-name
├── build.sbt # sbt项目配置
├── project
│ └── build.properties
└── src
└── main
└── scala
└── Main.scala # 入口程序
项目配置
build.sbt
:
name := "HelloWorld"
version := "1.0"
scalaVersion := "2.13.8" # *
*
:项目可指定Scala版本而无需使用全局Scala版本。
开发环境
Coursier管理工具
Coursier命令行工具用于安装Scala应用程序和设置开发环境1。
安装Coursier
==如果安装过程无法下载数据,首先检查网络状况,可能需要设置代理。==
Linux
CS_URL=https://github.com/coursier/launchers/raw/master/cs-x86_64-pc-linux.gz
curl -fL $CS_URL | gzip -d > cs && chmod +x cs && ./cs [options] setup [options]
将安装coursier
(cs
)到默认位置,以及安装以下全局命令行工具和JVM(安装过程会提示是否更新用户配置文件(.profile
)中的环境变量,从而使相应工具全局可用):
scala-cli
, a convenient tool to compile / run / package Scala codescala
, the Scala REPLscalac
, the Scala compilersbt
andsbtn
, the sbt build toolsammonite
, an enhanced REPL for Scalascalafmt
, the Scala code formatter
安装完成后可移除下载的cs
文件,使用安装版本的couriser/cs
进行管理。
cs setup \
--apps sbt-launcher,ammonite \ # 安装额外的命令行工具
--install-dir ~/.local/scala \ # 修改安装目录*
--yes # 使用默认选项,取消交互
*
:--install-dir
仅适用于cs
以及scala
工具,不适用于JVM安装路径。
Windows
$Uri="https://github.com/coursier/launchers/raw/master/cs-x86_64-pc-win32.zip"
Invoke-WebRequest -Uri $Uri -OutFile "cs-x86_64-pc-win32.zip"
Expand-Archive -Path "cs-x86_64-pc-win32.zip"
.\cs-x86_64-pc-win32.exe setup
get-command cs # 重新打开终端执行
安装完成后,将自动添加Coursier
目录C:\Users\USER\AppData\Local\Coursier\data\bin
到路径环境变量中(如果未添加,可手动添加;如果不需要全局启用,可通过PowerShell $Profile
设置)。
$env:JAVA_HOME="C:\Users\gary\AppData\Local\Coursier\cache\arc\https\github.com\AdoptOpenJDK\openjdk8-binaries\releases\download\jdk8u292-b10\OpenJDK8U-jdk_x64_windows_hotspot_8u292b10.zip\jdk8u292-b10"
$env:PATH="$env:JAVA_HOME\bin;C:\tools\scala;$env:PATH"
配置Coursier
coursier网络代理配置
Coursier的JVM不会自动使用系统的代理配置,需要将代理配置通过Java选项传递给JVM。
coursier '-J-Dhttps.proxyHost=127.0.0.1' '-J-Dhttps.proxyPort=7890' [args] #*
sbt '-Dhttps.proxyHost=…' '-Dhttps.proxyPort=…' [args] #**
传递给
java.net.HttpURLConnection
的代理属性,HTTP同理。
*
:PowerShell会将-XX
解释为PowerShell命令的选项,需要使用''
将其视为普通参数传递。
**
:在环境变量JAVA_OPTS
中配置(仅适用于sbt
,不适用于coursier
):export JAVA_OPTS="$JAVA_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= ..."
仓库配置
仓库列表:~/.sbt/repositories
文件(不存在则手动创建)记录所有可用仓库列表。
[repositories]
local
maven-central
模板配置文件:delta/repositories at master · delta-io/delta (github.com)
默认仓库为:
ivy2local
:Ivy2本地仓库,位于~/.ivy2/local
;central
:Maven中央仓库,即https://repo1.maven.org/maven2
;
上述默认配置可通过环境变量COURSIER_REPOSITORIES
修改(使用镜像仓库代替Maven中央仓库central
)。或通过命令行选项-r,--repository
指定额外仓库(可指定多次以包含多个仓库)。提供--no-default
将不使用默认或通过环境变量配置的仓库。
export COURSIER_REPOSITORIES="ivy2Local|central|sonatype:releases|jitpack|http://"
sbt Reference Manual — Proxy Repositories sbt Configuration
sbt Reference Manual — sbt Launcher Configuration 3. Repositories Section
相应地,可在项目配置文件(优先级更高)中添加:
resolvers += "central" at "http://maven.aliyun.com/nexus/content/groups/public/"
externalResolvers :=
Resolver.withDefaultResolvers(resolvers.value, mavenCentral = false)
镜像配置:sbt
默认使用Maven中央仓库下载依赖,因此速度很慢。~/.config/coursier/mirror.properties
(Linux)中配置代理转发规则(类似于Maven配置的mirrorOf
)。
central.from=https://repo1.maven.org/maven2
central.to=https://mirrors.huaweicloud.com/repository/maven #*
*
:阿里云/163中央仓库镜像缺少部分Scala插件包,腾讯云下载文件可能校验和不一致,实测华为云镜像更新安装时不会报错。该配置文件路径可通过
COURSIER_MIRRORS
环境变量或命令行选项-Dcoursier.mirrors=
指定。
缓存路径
缓存用于存放不经常发生变化的依赖库,默认路径为~/.cache/coursier/v1
(Linux),配置COURSIER_CACHE
环境变量或coursier.cache
Java选项覆盖默认路径。
coursier
使用的缓存路径:传递--cache
选项覆盖上述配置;sbt
使用的缓存路径:其位置可在sbt
交互环境中使用show csrCacheDirectory
查看。通过或传递-Dsbt.coursier.home
选项来更改缓存路径。
缓存声明周期:以-SNAPSHOT
结尾的包、Maven元数据等具有缓存周期(TTL,默认为24小时)。
管理Scala命令行应用程序
cs install <app:version> --install-dir DIR # -> cs setup --apps <app:version>
cs list|update|uninstall|search <app:version>
默认安装位置:~/.local/share/coursier/bin
,可通过配置修改;需要将安装位置加入PATH
以便通过命令名启动应用。环境变量COURSIER_BIN_DIR|COURSIER_INSTALL_DIR
以及Java属性coursier.install.dir
可覆盖上述默认位置(优先级由高到低)。==命令行选项--dir,--install-dir
具有最高优先级==。
管理JVM
cs java --available # 列出可用Java版本
cs java --installed # 列出已安装Java版本
cs setup --jvm 11 # 安装Java环境*
cs java --jvm 11 --env # 输出设置Java环境变量的语句,可调用eval执行
cs java --jvm 11 [options] args... # 使用指定Java(不存在则自动下载安装)**
cs java --jvm VER --setup # 设置默认Java版本
cs java-home [--jvm ver]... # 显示指定环境的JAVA_HOME
cs
会首先检查系统是否自带Java并尝试使用该版本;如果没有,则自动安装AdoptOpenJDK 1.8。通过--jvm
指定的Java即使与自带版本相同(如1.8
)还是会额外下载安装,如果版本仅指定数字,默认安装Adoptium发布的JDK(adoptium
,与AdoptOpenJDK标识adopt
不同)。安装后会提示是否更新环境变量,环境变量决定命令行工具依赖的Java版本。如果使用指定版本Java执行命令时,该版本不存在,则
cs
会自动下载安装相应版本Java。Adoptium OpenJDK是从GitHub下载,可能需要使用代理。
*
:--jvm-dir
(指定Java安装路径)不可用。JVM安装路径可通过COURSIER_JVM_CACHE
或coursier.jvm.cache
Java系统属性设置。
启动Scala应用
install
命令会将安装的应用存放在上述路径下,因此通过命令名启动应用程序则是最近安装的版本。
app [options] args... # 启动默认版本
如果要启动其他版本,使用cs launch
命令。
cs launch <app:version> [cs_options] -- [app_args...] # app未经安装则直接从仓库源拉取
# cs launch scala:2.12.15
cs launch org.scalameta::scalafmt-cli:2.4.2
-M,--main-class # 如果指定的库找不到主类,可通过该选项指定
-java-opt -Dfoo=bar --java-opt -Xmx2g # 传递Java参数给应用
应用程序支持接收Java运行时参数,如
"-J-Xmx2g"
;或通过环境变量设置,两种可混合使用。export JAVA_OPTS="-Xmx2g -Dfoo=bar"
bootstrap
将从指定的依赖库构造可执行的应用程序文件。
cs bootstrap org.scalameta::scalafmt-cli:2.4.2 -o scalafmt
配置应用程序通道
默认使用主通道,即io.get-coursier:apps
。
cs install --contrib app # io.get-coursier:apps-contrib*
--channel <custom-channel>
*
:app
和io.get-coursier:apps-contrib
是官方维护的仓库通道。
管理Maven依赖项
解析依赖项
cs resolve io.circe::circe-generic:0.12.3
下载依赖项
cs fetch io.circe::circe-generic:0.12.3
--classpath # 输出依赖包的CLASSPATH,而不是仅列出下载路径
--source # 下载源码包而非标准包
--javadoc # 下载文档而非标准包
--default=true # 同时下载标准包
Scala依赖库和应用程序
命令行工具
编译工具
sbt # 进入sbt交互环境
[~]run # 使用"~"可在文件发生更改时自动重新执行, 输入exit退出
sbt run # 直接编译运行
集成开发环境
集成开发环境可使用IntelliJ或VSCode。
VSCode+Metals
开发环境设置
设置下Metals语言服务器依赖库的仓库源。
{
"metals.customRepositories": [
"https://maven.aliyun.com/repository/central"
]
}
Metal项目设置
bloop