1.4 Scala语法基础
想要熟练掌握Scala语言,不可忽视Scala语言语法的学习。
1.4.1 定义变量
Scala的变量是如何定义的呢?
比如,我们在Java中以“变量类型 变量名 = 初始值”的方式定义学生年龄。
int studentAge = 18;
而在Scala中,我们需要通过不同的方式来确定变量是否不可变(只读):val/var变量名 : 变量类型 = 初始值。
变量类型可以指定,也可以不指定,由初始化的值决定。这种由初始化的值决定变量类型的方式叫作类型推断。var代表可变变量,val代表不可变变量。
使用定义格式定义变量的方法如下。
scala> var studentAge:Int =18
studentAge: Int = 18
使用类型推断的形式定义变量的方法如下。
scala> var studentAge =18
studentAge: Int = 18
那么var和val在什么地方不一样呢?现在使用var定义变量并修改值。
scala> var studentAge =18
studentAge: Int = 18
scala> studentAge = 19
studentAge: Int = 19
可以看到,使用var定义的学生年龄可以被修改。现在使用val定义变量并修改值。
scala> val studentAge =18
studentAge: Int = 18
scala> studentAge = 19
<console>:12: error: reassignment to val
studentAge=19
^
在修改使用val定义的学生年龄时报错,说明使用val定义的变量是只读的,不可修改。
1.4.2 惰性赋值
使用var或者val定义的变量会直接加载到JVM内存,但在一些大型计算场景下,如执行一条复杂SQL语句,这个SQL语句可能有成百上千行,直接加载到JVM内存可能会造成很大的内存开销。针对这种情形,Scala提供了一个更好的赋值方式,也就是惰性赋值。当一个变量需要保存很大的数据,且不想直接加载到JVM内存,而是等需要执行时再加载时可以使用惰性赋值。其语法格式为:lazy val/var 变量名 = 表达式。
scala> lazy val sql = """
| select a.student_name ,b.class_info, c.teacher_name
| from a ,b,c
| where a.student_name in b.student_name
| ... // 此为上百行查询条件
| group by a.class_score """
sql: String = <lazy>
1.4.3 字符串
Scala提供了多种字符串的定义方式,我们可以根据需要选择。具体定义方式和使用场景及其案例如下。
1.双引号
最简单的双引号,适用于大多数字符串定义,如定义一个学生的名称,值为Lisa。
scala> val studentName = "Lisa"
studentName: String = Lisa
2.插值表达式
插值表达式定义的语法格式为val/var 变量名 = s"${变量/表达式}字符串" ,适用于需要进行字符串拼接的场景,如定义一场考试的试卷信息,具体试卷类型由试卷编号和年级决定。
scala> val examNum = "001"
examNum: String = 001
scala> val classInfo = "classNo.1"
classInfo: String = classNo.1
scala> val examInfo = s"${classInfo}+${examNum}"
examInfo: String = classNo.1+001
3.三引号
三引号定义的语法格式为val 变量名 = """""",适用于有大段文字需要保存的场景,希望可以换行且不影响数据定义,方便阅读,如定义一个SQL语句。
scala> val sql = """
| select student_name, class_score, class_info
| from score_table
| where class_score > 90 """
sql: String =
" select student_name, class_score, class_info
from score_table
where class_score > 90 "
1.4.4 数据类型与运算符
Scala语言像其他编程语言一样有数据类型和运算符。
1.数据类型
Scala的数据类型和Java的大同小异。需要注意的是,Scala中所有数据类型的首字母都是大写的,整数类型是Int,而不是Integer(见表1-1)。
表1-1
2.运算符
Scala提供了丰富的内置运算符(见表1-2),主要作用是告诉编译器执行特定的数学或逻辑函数运算。
表1-2
注意,Scala中没有++和--这两种运算符。要比较两个值是否相等,直接使用==或者!=即可,它们相当于Java中的equals。
scala> var a =0
a: Int = 0
scala> a++
<console>:13: error: value ++ is not a member of Int
a++
^
scala> var b =0
a: Int = 0
scala> b--
<console>:13: error: value -- is not a member of Int
b--
^
3.Scala类型层次结构
Any是所有类型的父类,定义了一些通用的方法,如toString、equals、hashCode等。Any有两个子类:AnyVal是所有数值类型的父类,AnyRef是所有对象类型(引用类型)的父类。Nothing是所有类型的子类型,但是没有一个值是Nothing类型的,它的主要作用是给出非正常终止的信号,比如抛出异常、程序退出等。Null是所有引用类型的子类型,即AnyRef的子类,它由值null来表示,多用于和其他语言的互操作。
1.4.5 条件表达式
条件表达式就是if表达式,根据条件执行对应的命令。
1.有返回值的if表达式
Java中的if表达式是没有返回值的,如定义变量a =1、变量b=2,如果变量a等于变量b,则返回true,否则返回false。
scala> val a = 1
a: Int = 1
scala> val b = 2
b: Int = 2
scala> if (a == b) "true" else "false"
res2: String = false
可以看出,if表达式的返回值为false。在Java中,需要再定义一个变量去赋值,才能得到命令执行后的值。
Scala没有为三元运算设计特定的运算符,我们可以利用if表达式带有返回值的特性来模拟。
scala> val c = if (a == b) "true" else "false"
c: String = false
2.块表达式
块表达式用于多行处理语句赋值一个变量,多行处理语句用{}包裹后作用于一个变量。
scala> val c = {
| print("c result is")
| if (a == b) "true" else "false"
| }
c result is c: String = false
注意,上面示例中的if判断语句,其返回false,则c的值为false。那么,如果我们将print放在最后一行会有什么变化呢?
scala> val c = {
| if (a == b) "true" else "false"
| print("c result is ")
| }
c result is c: Unit = ()
c的值变为null,这是因为print的返回值为null。