一、Scala基础之变量、运算符、程序流程控制
Scala基础之变量、运算符、程序流程控制
文章目录
一、变量
1.1 Scala变量使用说明
变量声明基本语法
1 | var | val 变量名 [: 变量类型] = 变量值 |
注意事项
-
声明变量时,类型可以省略(编译器自动推导,即类型推导)
-
类型确定后,就不能修改,说明Scala 是强数据类型语言
1 | var a:Int=10 |
-
在声明/定义一个变量时,可以使用var 或者 val 来修饰, var 修饰的变量可改变,val 修饰的变量不可改
-
val修饰的变量在编译后,等同于加上final,通过反编译看下底层代码。
-
var 修饰的对象引用可以改变,val 修饰的则不可改变,但对象的状态或属性(值)却是可以改变的。(比如: 自定义对象、数组、集合等等) ,因此一般用val修饰对象。
-
变量声明时,需要初始值
1.2 scala数据类型
1)Scala各类型数据有固定的表数范围和字段长度,不受具体OS的影响,以保证Scala程序的可移植性。
2) Scala的整型 常量/字面量 默认为 Int 型,声明Long型 常量/字面量 须后加l
或L
3)Scala的浮点型常量默认为Double型,声明Float型常量,须后加f
或F
4)浮点型常量有两种表示形式
十进制数形式:如:5.12 512.0f .512 (必须有小数点)
科学计数法形式:如:5.12e2 = 5.12乘以10的2次方 5.12E-2 = 5.12除以10的2次方
1.3 Unit类型、Null类型和Nothing类型
- Null类只有一个实例对象,null,类似于Java中的null引用。null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal: 比如 Int, Float, Char,Boolean, Long, Double, Byte, Short)。
注意:Int被反编译为int,因此Scala中的AnyVal都是值类型
1 | val a:StringOps=null |
- Unit类型用来标识过程,也就是没有明确返回值的函数。由此可见,Unit类似于Java里的void。Unit只有一个实例,(),这个实例也没有实质的意义
1 | def main(args: Array[String]): Unit = { |
3)Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。
1 | def main(args: Array[String]): Unit = { |
1.4 值类型隐式转换
Scala程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数据类型,这个就是自动类型转换(隐式转换)。
数据类型按精度(容量)大小排序为
-
有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算,如
5.6 + 10 = 》double
-
当我们把精度(容量)大 的数据类型赋值给精度(容量)小 的数据类型时,就会报错,反之就会进行自动类型转换。
-
(byte, short) 和 char之间不会相互自动转换。
-
byte,short,char 他们三者可以计算,在计算时首先转换为int类型。
- 自动提升原则: 表达式结果的类型自动提升为 操作数中最大的类型
1.5 强制类型转换
自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。
java : int num = (int)2.5
scala : var num : Int = 2.7.toInt
(scala中所有的基本类型数据都是一个对象,这点和java不同)
强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
1 | val num1: Int = 10 * 3.5.toInt + 6 * 1.5.toInt // 36 |
1.6 值类型和String类型的转换
在程序开发中,我们经常需要将基本数据类型转成String 类型,或者将String类型转成基本数据类型。
基本类型转String类型
语法: 将基本类型的值+"" 即可
String类型转基本数据类型
语法:通过基本类型的String的 toXxx方法即可
在将String 类型转成 基本数据类型时,要确保String类型能够转成有效的数据,比如 我们可以把 “123” , 转成一个整数,但是不能把 “hello” 转成一个整数。
1.7 标识符的命名规范
- Scala 对各种变量、方法、函数等命名时使用的字符序列称为标识符
- 凡是自己可以起名字的地方都叫标识符
Scala中的标识符声明,基本和Java是一致的,但是细节上会有所变化。
-
首字符为字母,后续字符任意字母和数字,美元符号,可后接下划线_
-
数字不可以开头。
-
首字符为操作符(比如+ - * / ),后续字符也需跟操作符 ,至少一个
-
操作符(比如±*/)不能在标识符中间和最后
-
用反引号`…`包括的任意字符串,即使是关键字(39个)也可以,如
标识符举例说明
1 | `public` //ok |
一定要注意:
1 | var ++ = 10 //ok,这里++为变量名 |
二、运算符
运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。
- 算术运算符
- 赋值运算符
- 比较运算符(关系运算符)
- 逻辑运算符
- 位运算符
2.1 算术运算符
算术运算符(arithmetic)是对数值类型的变量进行运算的,在Scala程序中使用的非常多。
算数运算符的运算规则和Java一样。
Scala中没有++、–操作符,需要通过+=、-=来实现同样的效果
2.2 关系运算符(比较运算符)
-
关系运算符的结果都是boolean型,也就是要么是true,要么是false
-
关系表达式 经常用在 if结构的条件中或循环结构的条件中
-
关系运算符的使用和java一样
-
使用陷阱: 如果两个浮点数进行比较,应当保证数据类型一致
1 | var a = 9 |
2.3 逻辑运算符
用于连接多个条件(一般来讲就是关系表达式),最终的结果也是一个Boolean值。
假定变量 A 为 true,B 为 false
2.4 赋值运算符
这部分的赋值运算涉及到二进制相关知识,其运行的规则和Java一样。
2.5 位运算符
说明: 位运算符的规则和Java一样
Scala不支持三目运算符 , 在Scala 中使用 if – else 的方式实现。
1 | val num = 5 > 4 ? 5 : 4 //没有 |
2.6 运算符优先级
运算符的优先级和Java一样。
小结运算符的优先级
1.() []
2.单目运算
3.算术运算符
4.移位运算
5.比较运算符(关系运算符)
6.位运算
7.关系运算符
8.赋值运算
2.7 键盘输入语句
1 | import scala.io.StdIn |
2.8 多种print输出方式
(1)普通输出方式:
1 | object HelloWorld { |
(2)插值字符串输出方式:
1 | object HelloWorld { |
这样的好处是可以少些+号,避免字符串拼写错误出现。
(3)格式化输出
1 | object HelloWorld { |
printf方法常用格式说明符列表
%c 单个字符
%d 十进制整数
%f 十进制浮点数
%o 八进制数
%s 字符串
%u 无符号十进制数
%x 十六进制数
%% 输出百分号%
举例,“%s:%.2f”是格式字符串,其中“%s”表示输出字符串,“%.2f”表示输出浮点数时,限制2位有效小数,更改“%.”后面的数字,可以限制不同的小数位数输出
三、程序流程控制
Scala语言中控制结构和Java语言中的控制结构基本相同,在不考虑特殊应用场景的情况下,代码书写方式以及理解方式都没有太大的区别。
- 顺序控制
- 分支控制
- 循环控制
3.1 分支控制if-else
和java完全一样
Scala中是没有三元运算符,因为可以这样简写
1 | // Java |
scala中的if-else是有返回值的,因此,本身这个语言也不需要三元运算符了,并且可以写在同一行,类似 三元运算
分支控制if-else 注意事项
上面输出if-else结构的返回值
3.2 switch分支结构
在scala中没有switch,而是使用模式匹配来处理。
模式匹配涉及到的知识点较为综合,因此我们放在后面讲解:match-case
3.3 for循环控制
Scala 也为for 循环这一常见的控制结构提供了非常多的特性,这些for 循环的特性被称为for 推导式(for comprehension)或for 表达式(for expression)
(1)范围数据循环方式1
1 | for(i <- 1 to 3){ |
说明
- i 表示循环的变量,
<-
规定好 to 规定 - i 将会从 1-3 循环, 前后闭合
(2)范围数据循环方式2
1 | for(i <- 1 until 3) { |
说明:
- 这种方式和前面的区别在于 i 是从1 到 3-1
- 前闭合后开的范围,和java的arr.length() 类似
for (int i = 0; i < arr.lenght; i++){}
(3)循环守卫
1 | for(i <- 1 to 3 if i != 2) { |
- 循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为true则进入循环体内部,为false则跳过,类似于
i==2
时执行continue - 上面的代码等价
1 | for (i <- 1 to 3) { |
(4)引入变量
1 | for(i <- 1 to 3; j = 4 - i) { |
- 没有关键字,所以范围后一定要加
;
来隔断逻辑 - 上面的代码等价
1 | for ( i <- 1 to 3) { |
(5)嵌套循环
1 | for(i <- 1 to 3; j <- 1 to 3) { |
- 没有关键字,所以范围后一定要加
;
来隔断逻辑 - 上面的代码等价
1 | for ( i <- 1 to 3) { |
(6)循环返回值
1 | val res = for(i <- 1 to 10) yield i |
- 将遍历过程中处理的结果返回到一个新Vector集合中,使用yield关键字
(7)使用花括号{}代替小括号()
1 | for(i <- 1 to 3; j = i * 2) { |
可以写成
1 | for{ |
- {}和()对于for表达式来说都可以
- for 推导式有一个不成文的约定:当for 推导式仅包含单一表达式时使用圆括号,当其包含多个表达式时使用大括号
- 当使用{} 来换行写表达式时,分号就不用写了
(8)注意事项和细节说明
- scala 的for循环形式和java是较大差异,,但是基本的原理还是一样的。
- scala 的for循环的步长如何控制
1 | for(i <- Range(1,10,2))//Range是1至10左闭右开,步长为2 |
或者写成
1 | for(i <- 1 until 10) { |
下面这种写法是错误的,一定要注意
1 | for(i <- 1 until 10) { |
3.4 while循环控制
1 | 循环变量初始化 |
注意事项和细节说明
- 循环条件是返回一个布尔值的表达式
- while循环是先判断再执行语句
- 与If语句不同,While语句本身没有值,即整个While语句的结果是Unit类型的()
- 因为while中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免的使用变量 ,而变量需要声明在while循环的外部,那么就等同于循环的内部对外部的变量造成了影响,所以不推荐使用,而是推荐使用for循环。
3.5 do…while循环控制
1 | 循环变量初始化; |
注意事项和细节说明
- 循环条件是返回一个布尔值的表达式
- do…while循环是先执行,再判断
- 和while 一样,因为do…while中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免的使用变量 ,而变量需要声明在do…while循环的外部,那么就等同于循环的内部对外部的变量造成了影响,所以不推荐使用,而是推荐使用for循环
3.6 for或while循环的中断
Scala内置控制结构特地去掉了break和continue,是为了更好的适应函数化编程,推荐使用函数式的风格解决break和contine的功能,而不是一个关键字。
(1)实现break的效果
1 | import scala.util.control.Breaks.{break, breakable} |
(2)实现continue的效果
Scala内置控制结构特地也去掉了continue,是为了更好的适应函数化编程,可以使用if – else 或是 循环守卫实现continue的效果
1 | for (i <- 1 to 10 if (i != 2 && i != 3)) { |
等同于
1 | for(int i=0;i<=10;i++) |