官网:https://www.scala-lang.org/
概述
Scala编程语言是一款多范式的编程语言,即纯面向对象又是函数式编程的一款高级语言;支持类型推断(推断)可以在复杂的应用避免一些不必要的错误;Scala的应用程序运行在JVM(java 虚拟机)之上,可以无缝的和Java语言进行互操作;并且提供了一个规模庞大的生态系统,可以简化复杂应用的开发;
特点
- 无缝和Java进行互操作
- 类型推导(推断)
- 天生支持并发和分布式开发
- 功能强大的特质(trait)类
- 模式匹配(值、类型、元素、元素类型等)
- 高阶函数(函数是Scala编程语言中的一等公民)
环境搭建
准备工作:需要JDK1.8以及以上
安装:安装 scala版本是2.11.12
win + r -> cmd -> scala -version
检测是否安装成功
IDEA 集成Scala插件
plugins 中搜索 scala 下载安装,打开项目设置添加外部依赖
使用
Scala 窗口命令使用
REPL: R (读取) E (评估) P(打印) L(循环)
win + r -> cmd -> scala
回车进入Scala 的命令窗口模式
scala> 1+1
res1: Int = 2
scala> 2+2
res2: Int = 4
注意: res2: Int = 4 声明变量语法: 变量名 : 类型 = 值
传统用法
手动书写scala的源文件,先编译后解释执行;
scala源文件.scala
—>scalac 源文件.scala
—>.class(字节码文件)
—>scala .class字节码文件名
object HelloWorld{
// scala主函数
def main(args:Array[String]):Unit = {
println("Hello World")
}
}
编译运行
D:\>scalac HelloWorld.scala
D:\>scala HelloWorld
Hello World
变量和常量
Scala 与 Java有着相同的数据类型,下表列出了 Scala 支持的数据类型:
数据类型 | 描述 |
---|---|
Byte | 8位有符号补码整数。数值区间为 -128 到 127 |
Short | 16位有符号补码整数。数值区间为 -32768 到 32767 |
Int | 32位有符号补码整数。数值区间为 -2147483648 到 2147483647 |
Long | 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 |
Float | 32位IEEE754单精度浮点数 |
Double | 64位IEEE754单精度浮点数 |
Char | 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF |
String | 字符序列 |
Boolean | true或false |
Unit | 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 |
Null | null 或空引用 |
scala> 3*4
res5: Int = 12
scala> 1*0.5
res6: Double = 0.5
scala> true
res7: Boolean = true
scala> false
res8: Boolean = false
scala> "abc"
res9: String = abc
scala> 'c'
res10: Char = c
注意:
- scala中变量的类型支持自动推导: 整数(Int) 、小数(Double) 其它(略)
- scala中基本类型
scala.*
,如:scala.Int或scala.Double
; scala中的字符串类型:java.lang.String
声明变量
语法:var 变量名 : 类型 = 值
# 1. 完整写法
scala> var a : Int = 10
a: Int = 10
scala> println(a)
10
# 2. 简化写法
scala> var b = 20
b: Int = 20
scala> var c = 30L
c: Long = 30
scala> var d:Long = 40
d: Long = 40
scala> var c = 30L
c: Long = 30
scala> var f : Float = 30.1f
f: Float = 30.1
scala> var date = new java.util.Date()
date: java.util.Date = Mon Jan 06 11:44:58 CST 2020
注意:
- 变量的值是允许重复更改的
- 声明变量时,不添加类型则使用类型推导;如果添加类型信息,则使用指定的类型;
声明常量
语法:val 常量名:类型 = 值
scala> val a1:Int = 10
a1: Int = 10
scala> a1 = 20
<console>:12: error: reassignment to val
a1 = 20
^
注意:
- 常量只允许赋值一次
- 常量值类型值不可变,引用类型是地址不可变
- 在scala中除过特殊的需求外,建议使用常量;
运算符
- 赋值运算符:
=
- 关系运算符:
> 、< 、<= 、>= 、!=、 ==
- 逻辑运算符:
&& (与)、 || (或) 、!(非)
- 位运算符:
& 、| 、~ 、^、<<、 >>、 >>>
- 算术运算符:
+、-、*、/、%
注意:scala没有
++
和--
语法,但是依然保留了+=
和-=
# 1. 从右向左执行 将10赋值给变量a1
scala> var a1 = 10
a1: Int = 10
# 2. 关系运算符 比较判断 得到Boolean值
scala> 1 > 2
res13: Boolean = false
scala> 1 < 2
res14: Boolean = true
scala> 2 <= 2
res15: Boolean = true
# 注意: scala做到严格意义上的万物皆对象 运算符实际上都是对象中的方法
scala> 1.<(2)
res21: Boolean = true
scala> 1 + 1
res22: Int = 2
scala> 1.+(1)
res23: Int = 2
# 3. 逻辑运算符
scala> true || false
res26: Boolean = true
scala> !true
res27: Boolean = false
scala> !false
res28: Boolean = true
# 4. 算数运算符
scala> 1.*(2)
res34: Int = 2
scala> 3/6
res35: Int = 0
scala> 6/2
res36: Int = 3
scala> 6./(2)
res37: Int = 3
scala> 6%4
res38: Int = 2
scala> 6.%(4)
res39: Int = 2
# 5. 位运算 (二进制运算)
# && 和 & 逻辑 "与" 不具备短路运算
# & 位运算 相同的二进制位 同时为1 则结果为1
# | 有一个为1则结果为1 不同为0
# ^ 异或 相同为0,不同为1
# ~ 按位取反
# >> 右移
# << 左移
# >>> 无符号右移 不论是负数还正数 移动后都是正数
# 3: 00000011 >> 1 00000001
# 5: 00000101
# 3 & 5 = 1
# 3 | 5 = 7
# 3 ^ 5 = 00000110 = 6
# ~3 = 11111100 = -4
# 3 >> 1
类型转换
值类型可以进行转换
值类型可以按照下面的方向进行转换
scala> var b1 :Byte = 10
b1: Byte = 10
scala> var s1:Short = b1
s1: Short = 10
scala> var i1:Int = s1
i1: Int = 10
scala> var i2:Int = 'c'
i2: Int = 99
scala> b1 = i1
<console>:13: error: type mismatch;
found : Int
required: Byte
b1 = i1
^
Scala 类型层次结构
Any
是所有类型的超类型,也称为顶级类型。它定义了一些通用的方法如equals
、hashCode
和toString
。Any
有两个直接子类:AnyVal
和AnyRef
。AnyVal
代表值类型。有9个预定义的非空的值类型分别是:Double
、Float
、Long
、Int
、Short
、Byte
、Char
、Unit
和Boolean
。Unit
(类似于java中的void
)是不带任何意义的值类型,它仅有一个实例可以像这样声明:()
。所有的函数必须有返回,所以说有时候Unit
也是有用的返回类型。AnyRef
代表引用类型。所有非值类型都被定义为引用类型。在Scala中,每个用户自定义的类型都是AnyRef
的子类型。如果Scala被应用在Java的运行环境中,AnyRef
相当于java.lang.Object
。Nothing
是所有类型的子类型,也称为底部类型。没有一个值是Nothing
类型的。它的用途之一是给出非正常终止的信号,如抛出异常、程序退出或者一个无限循环(可以理解为它是一个不对值进行定义的表达式的类型,或者是一个不能正常返回的方法)。Null
是所有引用类型的子类型(即AnyRef
的任意子类型)。它有一个单例值由关键字null
所定义。Null
主要是使得Scala满足和其他JVM语言的互操作性,但是几乎不应该在Scala代码中使用。我们将在后面的章节中介绍null
的替代方案。
scala> :paste
// Entering paste mode (ctrl-D to finish)
val list: List[Any] = List(
"a string",
732, // an integer
'c', // a character
true, // a boolean value
() => "an anonymous function returning a string"
)
// Exiting paste mode, now interpreting.
list: List[Any] = List(a string, 732, c, true, <function0>)
scala> list.foreach(n => println(n))
a string
732
c
true
<function0>
Scala 输入输出
- 输出
打印输出值,需要使用
println
函数,println(s" = ${}")
也有带有C风格格式化字符串的函数printf("Hello, %s! You are %d years old.\n","Fred",44) // Hello, Fred! You are 44 years old.
- 输入
输出值,使用
readLine
函数从控制台读取一行输入readDouble
,readByte
等不同类型的输入
分支语句
类似于Java的分支语句
if语句
if(布尔表达式){
// 代码块
}
如:
scala> if(age >= 18){
| println("成年人")
| }
成年人
scala> if(age >= 18) println("成年人")
成年人
scala> var m = if(age >= 18) println("成年人")
成年人
m: Unit = ()
scala> var n = if(age >= 18){
| println("成年人")
| 1
| }
成年人
n: AnyVal = 1
scala> var x = if(age >= 18){ println("成年人"); 1; }
成年人
x: AnyVal = 1
if…else… 语句
if(布尔表达式){
// true
}else{
// false
}
scala> if(age > 18){
| println("成年人")
| }else{
| println("未成年人")
| }
未成年人
if…else if…else语句
if(布尔表达式1){
// true
}else if(布尔表达式2){
// true
}...else{
// false
}
var age = 18
scala> if(age > 60){
| println("老年人")
| }else if(age > 40){
| println("中年人")
| }else if(age >= 18){
| println("青年人")
| }else{
| println("未成年人")
| }
青年人
match匹配语句
替换java
switch...case
语句
scala> age match{
| case 18 => println("18岁")
| case 20 => println("20岁")
| case _ => println("默认的")
| }
18岁
scala> var age = 25
age: Int = 25
scala> age match{
| case a1 if(a1 >= 40) => println("中年人")
| case a2 if(a2 >= 20) => println("青年人")
| case _ => println("其它")
| }
青年人
注意:
- scala的match匹配语句,不会存在匹配穿透问题;
- scala的match匹配语句,default默认的匹配规则使用的是
_
- scala的match匹配语句,目前只使用到了值的匹配
循环语句
while语句
while(布尔表达式){
// 循环体内容
}
# 计算1+2+3...+100整数之和 5050
var m = 1
var sum = 0
while(m <= 100){
sum += m
m += 1
}
println(sum)
do…while语句
do{
// 循环体
}while(布尔表达式)
# 计算1+2+3...+100整数之和 5050
var m = 1
var sum = 0
do{
sum += m
m += 1
}while(m <= 100)
println(sum)
for循环语句
for(遍历产生的临时变量 <- 数值区间对象 | 集合 | 数组){
// 循环体
}
scala> 1 to 10
res72: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8
, 9, 10)
scala> 1 until 10
res73: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> 1 to 10 by 2
res74: scala.collection.immutable.Range = Range(1, 3, 5, 7, 9)
# 计算1+2+3...+100整数之和 5050
var sum = 0
for(n <- 1 to 100){
sum += n
}
println(sum)
注意:
- 数值区间对象,代表的是一个
Range
对象,构建方法有:n to m
(包含起始n和结束m) 或n until m
(包含起始但不包含结束m) , 设定步长增幅
嵌套for循环
# 九九乘法表
for(m <- 1 to 9){
for(n <- 1 to m){
print(n+"*"+m+"="+(m*n) +"\t")
}
println()
}
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
# 注意: 多重循环可以写在一个for中
for(m<- 1 to 9; n <- 1 to m){
print(n+"*"+m+"="+(m*n) +"\t")
if(m == n) {
println()
}
}
for循环中if守卫
# 遍历展示 1 to 10 数值区间的奇数,并且不能是5
for(n <- 1 to 10 by 2){
if(n != 5) println(n)
}
# 另外一种if写法 守卫语法
for(n <- 1 to 10 by 2 if n != 5 && n != 7){
println(n)
}
continue和break
注意:scala中没有
continue
和break
关键字;
continue
建议使用if守卫代替;break
中止循环;可以使用scala特殊类Breaks类实现等价效果
import scala.util.control.Breaks
object HelloWorld {
// 主函数
def main(args: Array[String]): Unit = {
// 可能会发出终止信号的代码 包裹起来
Breaks.breakable {
for (n <- 1 to 10) {
// 终止循环 1 2 3 4
if (n == 5) {
Breaks.break()
}
println(n)
}
}
}
}
//--------------------------------------------------
scala> import scala.util.control.Breaks
import scala.util.control.Breaks
scala> :paste
// Entering paste mode (ctrl-D to finish)
// 可能会发出终止信号的代码 包裹起来
Breaks.breakable {
for (n <- 1 to 10) {
// 终止循环 1 2 3 4
if (n == 5) {
Breaks.break()
}
println(n)
}
}
// Exiting paste mode, now interpreting.
1
2
3
4
yield关键字
for 循环中的 yield 会把当前的元素缓存下来,在遍历结束后返回一个新的集合
- 首先会将
yield
表达式的值会被加入存放到一个缓冲区中 - 在遍历结束之后,会返回一个基于缓冲区的新集合,类型为
Vector
- 新集合的元素的类型和遍历集合的类型是一致的
yield
在使用时,只有一行代码,代码块不能使用{}
// 2 4 6 8 => [6,12,18,24]
val v1 = for(n <- 1 until 10 if n %2 ==0) yield n*3
for(m <- v1){
println(m)
}