一、Scala基础之变量、运算符、程序流程控制

Scala基础之变量、运算符、程序流程控制

文章目录

一、变量

1.1 Scala变量使用说明

变量声明基本语法

1
var | val 变量名 [: 变量类型] = 变量值

注意事项

  1. 声明变量时,类型可以省略(编译器自动推导,即类型推导)

  2. 类型确定后,就不能修改,说明Scala 是强数据类型语言

1
2
var a:Int=10
a=10.5 //报错,类型确定后就不能修改
  1. 在声明/定义一个变量时,可以使用var 或者 val 来修饰, var 修饰的变量可改变,val 修饰的变量不可改

  2. val修饰的变量在编译后,等同于加上final,通过反编译看下底层代码。

  3. var 修饰的对象引用可以改变,val 修饰的则不可改变,但对象的状态或属性(值)却是可以改变的。(比如: 自定义对象、数组、集合等等) ,因此一般用val修饰对象。

  4. 变量声明时,需要初始值

1.2 scala数据类型

1)Scala各类型数据有固定的表数范围和字段长度,不受具体OS的影响,以保证Scala程序的可移植性。

2) Scala的整型 常量/字面量 默认为 Int 型,声明Long型 常量/字面量 须后加lL

3)Scala的浮点型常量默认为Double型,声明Float型常量,须后加fF

4)浮点型常量有两种表示形式
十进制数形式:如:5.12 512.0f .512 (必须有小数点)
科学计数法形式:如:5.12e2 = 5.12乘以10的2次方 5.12E-2 = 5.12除以10的2次方

1.3 Unit类型、Null类型和Nothing类型

  1. Null类只有一个实例对象,null,类似于Java中的null引用。null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal: 比如 Int, Float, Char,Boolean, Long, Double, Byte, Short)。

注意:Int被反编译为int,因此Scala中的AnyVal都是值类型

1
2
3
4
val a:StringOps=null
val b:String=null//说明String是引用类型
println(s"a=${a},b=${b}")//a=null,b=null
val c:Int=null//报错
  1. Unit类型用来标识过程,也就是没有明确返回值的函数。由此可见,Unit类似于Java里的void。Unit只有一个实例,(),这个实例也没有实质的意义
1
2
3
4
5
6
def main(args: Array[String]): Unit = {
println(fun())//输出()
}

def fun():Unit={
}

3)Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。

1
2
3
4
5
6
7
def main(args: Array[String]): Unit = {
test()//抛出异常
}

def test():Nothing={
throw new Exception("一个异常")
}

1.4 值类型隐式转换

Scala程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数据类型,这个就是自动类型转换(隐式转换)。

数据类型按精度(容量)大小排序为

  1. 有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算,如5.6 + 10 = 》double

  2. 当我们把精度(容量)大 的数据类型赋值给精度(容量)小 的数据类型时,就会报错,反之就会进行自动类型转换。

  3. (byte, short) 和 char之间不会相互自动转换。

  4. byte,short,char 他们三者可以计算,在计算时首先转换为int类型

  1. 自动提升原则: 表达式结果的类型自动提升为 操作数中最大的类型

1.5 强制类型转换

自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。

java : int num = (int)2.5
scala : var num : Int = 2.7.toInt (scala中所有的基本类型数据都是一个对象,这点和java不同)

强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级

1
2
3
val num1: Int = 10 * 3.5.toInt + 6 * 1.5.toInt  // 36
val num2: Int = (10 * 3.5 + 6 * 1.5).toInt // 44
println(num1 + " " + num2)

1.6 值类型和String类型的转换

在程序开发中,我们经常需要将基本数据类型转成String 类型,或者将String类型转成基本数据类型。

基本类型转String类型
语法: 将基本类型的值+"" 即可

String类型转基本数据类型

语法:通过基本类型的String的 toXxx方法即可

在将String 类型转成 基本数据类型时,要确保String类型能够转成有效的数据,比如 我们可以把 “123” , 转成一个整数,但是不能把 “hello” 转成一个整数。

1.7 标识符的命名规范

  1. Scala 对各种变量、方法、函数等命名时使用的字符序列称为标识符
  2. 凡是自己可以起名字的地方都叫标识符

Scala中的标识符声明,基本和Java是一致的,但是细节上会有所变化

  1. 首字符为字母,后续字符任意字母和数字,美元符号,可后接下划线_

  2. 数字不可以开头。

  3. 首字符为操作符(比如+ - * / ),后续字符也需跟操作符 ,至少一个

  4. 操作符(比如±*/)不能在标识符中间和最后

  5. 用反引号`…`包括的任意字符串,即使是关键字(39个)也可以,如

标识符举例说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
`public` //ok
hello // ok
hello12 // ok
1hello // error
h-b // error
x h // error
h_4 // ok
_ab // ok
Int // ok, 在scala中,Int 不是关键字,而是预定义标识符,可以用,但是不推荐
Float // ok
_ // 不可以,因为在scala中,_ 有很多其他的作用,因此不能使用
Abc // ok
+*- // ok
+a // error

一定要注意:

1
2
var ++ = 10 //ok,这里++为变量名
var ++= 10 //error,因为+=是数学运算

二、运算符

运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。

  1. 算术运算符
  2. 赋值运算符
  3. 比较运算符(关系运算符)
  4. 逻辑运算符
  5. 位运算符

2.1 算术运算符

算术运算符(arithmetic)是对数值类型的变量进行运算的,在Scala程序中使用的非常多。

算数运算符的运算规则和Java一样。

Scala中没有++、–操作符,需要通过+=、-=来实现同样的效果

2.2 关系运算符(比较运算符)

  1. 关系运算符的结果都是boolean型,也就是要么是true,要么是false

  2. 关系表达式 经常用在 if结构的条件中或循环结构的条件中

  3. 关系运算符的使用和java一样

  4. 使用陷阱: 如果两个浮点数进行比较,应当保证数据类型一致

1
2
3
4
5
6
7
8
9
var a = 9
var b = 8
println(a>b) // true
println(a>=b) // true
println(a<=b) // false
println(a<b) // false
println(a==b) // false
println(a!=b) // true
var flag : Boolean = a>b // true

2.3 逻辑运算符

用于连接多个条件(一般来讲就是关系表达式),最终的结果也是一个Boolean值。

假定变量 A 为 true,B 为 false

2.4 赋值运算符

这部分的赋值运算涉及到二进制相关知识,其运行的规则和Java一样。

2.5 位运算符

说明: 位运算符的规则和Java一样

Scala不支持三目运算符 , 在Scala 中使用 if – else 的方式实现。

1
2
val num = 5 > 4 ? 5 : 4  //没有
val num = if (5>4) 5 else 4

2.6 运算符优先级

运算符的优先级和Java一样。

小结运算符的优先级
1.() []
2.单目运算
3.算术运算符
4.移位运算
5.比较运算符(关系运算符)
6.位运算
7.关系运算符
8.赋值运算

2.7 键盘输入语句

1
2
3
4
5
6
7
8
9
10
11
12
import scala.io.StdIn
object InputDemo {

def main(args: Array[String]): Unit = {
var a:Int=StdIn.readInt()
var b:Double=StdIn.readDouble()
var c:String=StdIn.readLine()
println(a)
println(b)
println(c)
}
}

2.8 多种print输出方式

(1)普通输出方式:

1
2
3
4
5
6
7
8
object HelloWorld {
def main(args: Array[String]): Unit = {
var i:Int = 10
val j:Int = 20
println("Hello World")
println(i + j)
}
}

(2)插值字符串输出方式:

1
2
3
4
5
6
7
object HelloWorld {
def main(args: Array[String]): Unit = {
val name:String = "hikari"
val age:Int = 30
println(s"username = ${name}, age = ${age}")
}
}

这样的好处是可以少些+号,避免字符串拼写错误出现。

(3)格式化输出

1
2
3
4
5
6
7
8
object HelloWorld {
def main(args: Array[String]): Unit = {
val name:String = "hikari"
val age:Int = 30
//print(s"username = $name, age = $age")
printf("name = %s age = %d",name,age)
}
}

printf方法常用格式说明符列表

%c 单个字符

%d 十进制整数

%f 十进制浮点数

%o 八进制数

%s 字符串

%u 无符号十进制数

%x 十六进制数

%% 输出百分号%

举例,“%s:%.2f”是格式字符串,其中“%s”表示输出字符串,“%.2f”表示输出浮点数时,限制2位有效小数,更改“%.”后面的数字,可以限制不同的小数位数输出

三、程序流程控制

Scala语言中控制结构和Java语言中的控制结构基本相同,在不考虑特殊应用场景的情况下,代码书写方式以及理解方式都没有太大的区别。

  1. 顺序控制
  2. 分支控制
  3. 循环控制

3.1 分支控制if-else

和java完全一样

Scala中是没有三元运算符,因为可以这样简写

1
2
3
4
// Java
int result = flg ? 1 : 0
// Scala
val result = if (flg) 1 else 0

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
2
3
4
for(i <- 1 to 3){
print(i + " ")
}
println()

说明

  1. i 表示循环的变量, <-规定好 to 规定
  2. i 将会从 1-3 循环, 前后闭合

(2)范围数据循环方式2

1
2
3
4
for(i <- 1 until 3) {
print(i + " ")
}
println()

说明:

  1. 这种方式和前面的区别在于 i 是从1 到 3-1
  2. 前闭合后开的范围,和java的arr.length() 类似for (int i = 0; i < arr.lenght; i++){}

(3)循环守卫

1
2
3
4
for(i <- 1 to 3 if i != 2) {
print(i + " ")
}
println()
  1. 循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为true则进入循环体内部,为false则跳过,类似于i==2时执行continue
  2. 上面的代码等价
1
2
3
4
5
for (i <- 1 to 3) {
if (i != 2) {
println(i+"")
}
}

(4)引入变量

1
2
3
for(i <- 1 to 3; j = 4 - i) {
print(j + " ")
}
  1. 没有关键字,所以范围后一定要加来隔断逻辑
  2. 上面的代码等价
1
2
3
4
for ( i <- 1 to 3) {
val j = 4 –i
print(j+"")
}

(5)嵌套循环

1
2
3
for(i <- 1 to 3; j <- 1 to 3) {
println(" i =" + i + " j = " + j)
}
  1. 没有关键字,所以范围后一定要加来隔断逻辑
  2. 上面的代码等价
1
2
3
4
5
for ( i <- 1 to 3) {
for ( j <- 1to 3){
println(i + " " + j + " ")
}
}

(6)循环返回值

1
2
val res = for(i <- 1 to 10) yield i
println(res)//输出Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  1. 将遍历过程中处理的结果返回到一个新Vector集合中,使用yield关键字

(7)使用花括号{}代替小括号()

1
2
3
for(i <- 1 to 3; j =  i * 2) {
println(" i= " + i + " j= " + j)
}

可以写成

1
2
3
4
5
for{
i <- 1 to 3
j = i * 2} {
println(" i= " + i + " j= " + j)
}
  1. {}和()对于for表达式来说都可以
  2. for 推导式有一个不成文的约定:当for 推导式仅包含单一表达式时使用圆括号,当其包含多个表达式时使用大括号
  3. 当使用{} 来换行写表达式时,分号就不用写了

(8)注意事项和细节说明

  1. scala 的for循环形式和java是较大差异,,但是基本的原理还是一样的。
  2. scala 的for循环的步长如何控制
1
2
for(i <- Range(1,10,2))//Range是1至10左闭右开,步长为2
print(i+" ") //依次输出1 3 5 7 9

或者写成

1
2
3
4
for(i <- 1 until 10) {
if(i%2!=0)//使用守卫控制步长
print(i+" ")
}

下面这种写法是错误的,一定要注意

1
2
3
4
for(i <- 1 until 10) {
i+=2//因为i为val,是不允许更改的
print(i+" ")
}

3.4 while循环控制

1
2
3
4
5
循环变量初始化
while (循环条件) {
循环体(语句)
循环变量迭代
}

注意事项和细节说明

  1. 循环条件是返回一个布尔值的表达式
  2. while循环是先判断再执行语句
  3. 与If语句不同,While语句本身没有值,即整个While语句的结果是Unit类型的()
  4. 因为while中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免的使用变量 ,而变量需要声明在while循环的外部那么就等同于循环的内部对外部的变量造成了影响,所以不推荐使用,而是推荐使用for循环。

3.5 do…while循环控制

1
2
3
4
5
循环变量初始化;
do{
循环体(语句)
循环变量迭代
} while(循环条件)

注意事项和细节说明

  1. 循环条件是返回一个布尔值的表达式
  2. do…while循环是先执行,再判断
  3. 和while 一样,因为do…while中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免的使用变量 ,而变量需要声明在do…while循环的外部,那么就等同于循环的内部对外部的变量造成了影响,所以不推荐使用,而是推荐使用for循环

3.6 for或while循环的中断

Scala内置控制结构特地去掉了break和continue,是为了更好的适应函数化编程,推荐使用函数式的风格解决break和contine的功能,而不是一个关键字。

(1)实现break的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import scala.util.control.Breaks.{break, breakable}

object WhileBreak {
def main(args: Array[String]): Unit = {
breakable {
for (i <- 1 to 3) {
print(i+" ") //依次输出1 2
if (i == 2)
break();
}
}
println()
var n=1
breakable{
while(n<=20){
n+=1
//依次输出n=2,n=3,n=4,n=5,n=6,n=7,n=8,n=9,n=10,n=11,n=12,n=13,n=14,n=15,n=16,n=17,n=18
print("n="+n+",")
if(n==18)
break()
}
}
}
}

(2)实现continue的效果

Scala内置控制结构特地也去掉了continue,是为了更好的适应函数化编程,可以使用if – else 或是 循环守卫实现continue的效果

1
2
3
for (i <- 1 to 10 if (i != 2 && i != 3)) {
println("i=" + i)
}

等同于

1
2
3
4
5
6
for(int i=0;i<=10;i++)
if(i==2)
continue
if(i==3)
continue
System.out.println("i=" + i)