基础语法规则

  • 区分大小写

    Scala 语言对大小写敏感;

  • 类名

    对于所有的类名的第一个字母要大写。如果需要使用几个单词来构成一个类名,每个单词的第一个字母要大写;比如:ListDemo

  • 方法名

    所有方法名的第一个字母用小写。如果需要使用几个单词来构成方法名,除第一个单词外每个词的第一个字母应大写;比如:getResult

  • 程序文件名

    Scala 程序文件的后缀名是 .scala,程序文件的名称可以不与对象名称完全匹配。这点与 Java 有所区别。

    备注:建议遵循 Java 的惯例,程序文件名称与对象名称匹配;

  • main () 方法

    Scala 程序从 main () 方法开始处理,这是每一个 Scala 程序的入口点。main () 定义在 object 中;

  • 标识符

    所有 Scala 组件都需要名称,用于对象、类、变量和方法的名称称为标识符。

    关键字不能用作标识符,标识符区分大小写;

    标识符以字母或下划线开头,后面可以有更多的字母、数字或下划线;

    $ 字符是 Scala 中的保留关键字,不能在标识符中使用;


  • 注释

    Scala 使用了与 Java 相同的单行和多行注释;

  • 换行符

    Scala 语句可以用分号作为一行的结束,语句末尾的分号通常可以省略,但是如果一行里有多个语句那么分号是必须的。

  • 小结

    Scala 的基础语法与 Java 比较类似,但是仍然有三点不一样的地方:

    • 1、在 Scala 中换行符是可以省略的

    • 2、Scala 中 main 方法定义在 object 中

    • 3、Scala 中程序文件名可以不与对象名称相匹配,但是建议仍然遵循 Java 的规范,二者最好匹配

常用类型与字面量

数据类型 描述
Byte 8 位有符号补码整数。数值区间为 -128 到 127
Short 16 位有符号补码整数。数值区间为 -32768 到 32767
Int 32 位有符号补码整数。数值区间为 -2147483648 到 2147483647
Long 64 位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807
Float 32 位,IEEE 754 标准的单精度浮点数
Double 64 位 IEEE 754 标准的双精度浮点数
Char 16 位无符号 Unicode 字符,区间值为 U+0000 到 U+FFFF
String 字符序列
Boolean true 或 false
Unit 表示无值,相当于 Java 中的 void,用于不返回任何结果的方法的返回类型。Unit 写成 ()
Null 通常写成 null
Nothing Nothing 类型在 Scala 类层级的最低端,它是任何其他类型的子类型
Any Any 是 Scala 中所有类的超类
AnyRef AnyRef 是 Scala 中所有引用类的超类

Scala 和 Java 一样,有 8 种数值类型 Byte、Short、Int、Long、Float、Double、Char、Boolean 类型;

和 Java 不同的是 ,这些类型都是类,有自己的属性和方法。

Scala 并不刻意的区分基本类型和引用类型。

String 直接引用 Java.lang.String 中的类型,String 在需要时能隐式转换为 StringOps,因此不需要任何额外的转换,String 就可以使用 StringOps 中的方法。

每一种数据类型都有对应的 Rich 类型,如 RichInt、RichChar 等,为基本类型提供了更多的有用操作。

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
scala> 1.max(10)
res0: Int = 10

scala> 1.min(10)
res1: Int = 1

scala> 1.to(10)
res2: scala.collection.immutable.Range.Inclusive = Range 1 to 10

scala> 1.until(10)
res3: scala.collection.immutable.Range = Range 1 until 10

scala> 1 max(10)
res4: Int = 10

scala> 1 to(10)
res5: scala.collection.immutable.Range.Inclusive = Range 1 to 10

scala> "scala"*2
res6: String = scalascala

-- StringOps。 //toInt等方法都定义在StringLike中;StringOps实现了StringLike
scala> "11".toInt
res7: Int = 11

整数字面量。整数字面量有两种形式,十进制与十六进制 (0X/0x 开头)

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-- 十六进制整数字面量
scala> val a = 0xa
a: Int = 10

scala> val a = 0X00FF
a: Int = 255

scala> val magic = 0xcafe
magic: Int = 51966

-- 十进制整数字面量
scala> val dec1 = 255
dec1: Int = 255

scala> val dec1 = 31
dec1: Int = 31

-- Long类型整数字面量
scala> val magic = 0xcafeL
magic: Long = 51966

scala> val long1 = 255L
long1: Long = 255

-- Short 或 Byte 类型,需要明确声明,否则编译器会推断为Int类型
scala> val little: Short = 32767
little: Short = 32767

scala> val littler: Byte = 127
littler: Byte = 127

浮点数字面量

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
-- 十进制数、可选的小数点、可选的e开头的指数
scala> val big = 3.1415926
big: Double = 3.1415926

scala> val bigger = 3.1415926e1
bigger: Double = 31.415926

-- 浮点数字面量以F/f结尾为Float类型;否则为Double类型;
scala> val litte = 0.31415926f
litte: Float = 0.31415927

scala> val litte = 0.31415926e1F
litte: Float = 3.1415925

字符字面量

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
scala> val a = 'A'
a: Char = A

-- 用字符的Unicode码来表示。Unicode码前128个字符就是ASCII码
scala> val b = '\u0042'
b: Char = B

-- 转义字符
scala> val mark = '\'
<console>:1: error: unclosed character literal val mark = '\' ^

scala> val mark = '\\'
mark: Char = \

字符串字面量

plaintext
1
2
scala> val str = "Hello Scala"
str: String = Hello Scala

类层次结构

Scala 中,所有的类,包括值类型和引用类型,都最终继承自一个统一的根类型 Any。

Scala 中定义了以下三个底层类:

  • Any 是所有类型共同的根类型,Any 是 AnyRef 和 AnyVal 的超类

  • AnyRef 是所有引用类型的超类

  • AnyVal 是所有值类型的超类


上图中有三个类型需要注意:

  • Null 是所有引用类型的子类型

    Null 类只有一个实例对象 null。

    null 可以赋值给任意引用类型,但是不能赋值给值类型。

  • Nothing 位于 Scala 类继承关系的底部,它是其他所有其他类型的子类型

    • Nothing 对泛型结构有用 。比如,空列表 Nil 的类型就是 List [Nothing]

    • Nothing 的可以给出非正常终止的信号。比如,使用 Nothing 处理异常

  • Unit 类型用来标识过程,过程就是没有返回值的方法,Unit 类似于 Java 里的 void。Unit 只有一个实例 ()。

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- null 不能赋值给值类型
scala> val i: Int = null
<console>:11: error: an expression of type Null is ineligible for implicit conversion val i: Int = null

scala> val str: String = null
str: String = null

-- 使用 Nothing 处理异常
scala> val test = false
test: Boolean = false

scala> val thing: Int = if (test) 42 else throw new Exception("ERROR!")
java.lang.Exception: ERROR!
... 28 elided

-- Unit类型只有一个实例(),该实例没有实际意义
scala> val a = ()
a: Unit = ()

值与变量 & 自动类型推断

Scala 当中的声明变量可以使用以下两种方式:

  • val,值 – value,用 val 定义的变量,值是不可变的

  • var,变量 – variable,用 var 定义的变量,值是可变的

在 Scala 中,鼓励使用 val。大多数程序并不需要那么多的 var 变量。

声明变量时,可以不指定变量的数据类型,编译器会根据赋值内容自动推断当前变量的数据类型。

备注:简单数据类型可以省略,对于复杂的数据类型建议明确声明;

声明变量时,可以将多个变量放在一起声明。

plaintext
1
2
3
4
5
6
7
8
9
-- val定义的变量不可更改,变量的类型编译器可以进行自动类型推断
val name = "zhangsan"

-- 必要时可以指定数据类型
var name: String = null

-- 可以将多个值或变量放在一起声明
val x, y = 100;
var name, message: String = null

操作符

Scala 的算术操作符、位操作符与 Java 中的效果一样的。

需要特别注意一点:Scala 中的操作符都是方法

plaintext
1
2
a + b 等价 a.+(b)
1 to 10 等价 1.to(10)

书写时推荐使用:a + b 、1 to 10 这种代码风格。

Scala 没有提供 ++、-- 操作符,但是可以使用 +=、-=

块表达式和赋值语句

{} 块包含一系列表达式,其结果也是一个表达式,块中最后一个表达式的值就是块的值。

赋值语句返回 Unit 类型,代表没有值;

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
val x1 = 1
val y1 = 1
val x2 = 0
val y2 = 0
val distance = {
val dx = x1 - x2
val dy = y1 - y2
math.sqrt(dx*dx + dy*dy)
}
println(distance)

-- 赋值语句的值是Unit类型,不要把它们串接在一起。x的值是什么?
var y = 0
val x = y = 1

println(x)

结果:

plaintext
1
2
1.4142135623730951
()

输入和输出

通过 readLine 从控制台读取一行输入。

如果要读取数字、Boolean 或者字符,可以用 readInt、readDouble、readByte、readShort、readLong、readFloat、readBoolean 或者 readChar。

print、println、printf 可以将结果输出到屏幕;

scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
object ReadLineAndPrintDemo {
def main(args: Array[String]): Unit = {
print("请输入您的姓名:")
val name=scala.io.StdIn.readLine()
print("请输入您的年龄:")
val age=scala.io.StdIn.readInt()

println("您的姓名是:"+name+",年龄:"+age)
//printf是一个带有C语言风格的格式化字符串函数
printf("您的姓名是:%s,年龄:%d",name,age)
println()
println(s"您的姓名:$name,年龄:$age")
}
}

结果:

plaintext
1
2
3
4
5
请输入您的姓名:raoweijia
请输入您的年龄:26
您的姓名是:raoweijia,年龄:26
您的姓名是:raoweijia,年龄:26
您的姓名:raoweijia,年龄:26

字符串插值器

Scala 提供了三种字符串插值器:

  • s 插值器,对内嵌的每个表达式求值,对求值结果调用 toString,替换掉字面量中的那些表达式

  • f 插值器,它除 s 插值器的功能外,还能进行格式化输出,在变量后用 % 指定输出格式,使用 java.util.Formatter 中给出的语法

  • raw 插值器,按照字符串原样进行输出

scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
object InterpolatorDemo {
def main(args: Array[String]): Unit = {
//s插值器,可以通过$获取变量和表达式的值
val subject = "Scala"
val message = s"Hello,$subject"
println(message)

val array: Array[Int] = (1 to 10).toArray
val str = s"array.length=${array.length}"
println(str)

println(s"${10 * 9}")

//f插值器,用%指定输出格式
val year=2020
val month=8
val day=9
println(s"$year-$month-$day")
//以yyyy-MM-dd的方式显示,不足2位用0填充
println(f"$year-$month%02d-$day%02d")

//raw插值器,将字符串按原样输出
println("a\n\tc")
println(raw"a\nb\tc")
println("""a\nb\tc""")
}
}

结果:

plaintext
1
2
3
4
5
6
7
8
9
Hello,Scala
array.length=10
90
2020-8-9
2020-08-09
a
c
a\nb\tc
a\nb\tc

对象相等性

Java 中可以 == 来比较基本类型和引用类型:

  • 对基本类型而言,比较的是值的相等性

  • 对引用类型而言,比较的是引用相等性,即两个变量是否指向 JVM 堆上的同个对象

Scala 中,要比较两个基础类型的对象是否相等,可以使用 == 或!=;

scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object ObjectCompareDemo {
def main(args: Array[String]): Unit = {
println(1==1)
println(1!=2)
println(1==2)

val flag=List(1,2,3)==List(4,5,6)
println(flag)

println(List(1,2,3)!=Array(1,2,3))

//比较不同类型的对象
println(2==2.0)
println(List(1,2,3)=="Scala")
}
}

结果:

plaintext
1
2
3
4
5
6
7
true
true
false
false
true
true
false