Spark大数据实时计算:基于Scala开发实战
上QQ阅读APP看书,第一时间看更新

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。