基础语法规则

  • 区分大小写

    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等,为基本类型提供了更多的有用操作。

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开头)

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

浮点数字面量

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

字符字面量

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 = \

字符串字面量

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只有一个实例()。

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变量。

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

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

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

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中的操作符都是方法

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

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

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

块表达式和赋值语句

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

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

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)

结果:

1
2
1.4142135623730951
()

输入和输出

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

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

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

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")
}
}

结果:

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

字符串插值器

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

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

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

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

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""")
}
}

结果:

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中,要比较两个基础类型的对象是否相等,可以使用 == 或 !=;

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")
}
}

结果:

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