目录
g、数据类型自动转换
当 Scala 程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这 个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:
AnyVal | ||
Double | Unit | |
Float | StringOps | |
Long | ||
Int | <------> | Char |
Short | Boolean | |
Byte |
注:
- 自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成 精度大的那种数据类型,然后再进行计算。
- 把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动 类型转换。
- (byte,short)和 char 之间不会相互自动转换。
- byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型。
注意:Scala 还提供了非常强大的隐式转换机制(隐式函数,隐式类等),我们放在高 级部分专门用一个章节来讲解。
h、强制类型转换
自动类型转换的逆过程,将精度大的数值类型转换为精度小的数值类型。使用时要加上 强制转函数,但可能造成精度降低或溢出,格外要注意。
Java : int num = (int)2.5 | |
Scala : var num : Int = 2.7.toInt |
- 将数据由高精度转换为低精度,就需要使用到强制转换
- 强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
i、数值类型和String类型间的转换
注:
- 基本类型转 String 类型(语法:将基本类型的值+"" 即可)
- String 类型转基本数值类型(语法:s1.toInt、s1.toFloat、s1.toDouble、s1.toByte、s1.toLong、s1.toShort)
注意:在将 String 类型转成基本数值类型时,要确保 String 类型能够转成有效的数据,比如我 们可以把"123",转成一个整数,但是不能把"hello"转成一个整数。 var n5:Int = "12.6".toInt 会出现 NumberFormatException 异常。
扩展:
object TestType {
def main(args: Array[String]):Unit = {
//00000000 00000000 00000000 100000010
//var n:Int = 128
var n:Int = 130
var b:Byte = n.toByte
//10000000 为当前字节范围最小值,约定 -128
//负数补码:符号位不变,其他位按位取反 +1
println(b)
}
}
三、运算符
Scala运算符的使用基本和Java运算符相同,只有个别细节上不同。
a、算术运算符
运算符 | 运算 |
+ | 正号 |
- | 负号 |
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 取余 |
+ | 字符串连接 |
- 对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整 数部分而舍弃小数部分。
- 对一个数取模 a%b,和 Java 的取模规则一样
- println("r3=" + r3.formatted("%.2f")) // 含义:保留小数点 2 位,使用四舍五入
b、关系运算符(比较运算符)
运算符 | 运算 |
== | 等于 |
!= | 不等于 |
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
注意:
Java: ==比较两个变量本身的值,即两个对象在内存中的首地址; equals 比较字符串中所包含的内容是否相同。
Scala:==更加类似于 Java 中的 equals,参照 jd 工具
运算规则与java 一致。
c、逻辑运算符
用于连接多个条件(一般来讲就是关系表达式),最终的结果也是一个 Boolean 值。
运算符 | 描述 |
&& | 逻辑与 |
|| | 逻辑或 |
! | 逻辑非 |
b、赋值运算符
运算符 | 描述 |
= | 简单的赋值运算符,将一个表 达式的值赋给一个左值 |
+= | 相加后再赋值 |
-= | 相减后再赋值 |
*= | 相乘后再赋值 |
/= | 相除后再赋值 |
%= | 求余后再赋值 |
<<= | 左移后赋值 |
>>= | 右移后赋值 |
&= | 按位与后赋值 |
^= | 按位异或后赋值 |
|= | 按位或后赋值 |
注意:Scala 中没有++、--操作符,可以通过+=、-=来实现同样的效果;
c、位运算符
运算符 | 描述 |
& | 按位与运算符 |
| | 按位或运算符 |
^ | 按位异或运算符 |
~ | 按位取反运算符 |
<< | 左移动运算符 |
>> | 右移动运算符 |
>>> | 无符号右移 |
d、Scala运算符本质
在 Scala 中其实是没有运算符的,所有运算符都是方法。
- 当调用对象的方法时,点.可以省略
- 如果函数参数只有一个,或者没有参数,()可以省略
-
// 标准的加法运算 val i:Int = 1.+(1) // (1)当调用对象的方法时,.可以省略 val j:Int = 1 + (1) // (2)如果函数参数只有一个,或者没有参数,()可以省略 val k:Int = 1 + 1
;
四、流程控制
a、分支控制
让程序有选择的的执行,分支控制有三种:单分支、双分支、多分支
- 单分支
if (条件表达式) { 执行代码块 } 说明:当条件表达式为 ture 时,就会执行{ }的代码。
;
-
双分支
if (条件表达式) { 执行代码块 1 } else { 执行代码块 2 }
;
-
多分支
if (条件表达式 1) { 执行代码块 1 } else if (条件表达式 2) { 执行代码块 2 } …… else { 执行代码块 n }
- 注意:
- Scala 中 if else 表达式其实是有返回值的,具体返回值取决于满足条件的 代码体的最后一行内容。
- Scala 中返回值类型不一致,取它们共同的祖先类型。(Any)
- Java 中的三元运算符可以用 if else 实现 Scala:val res:Any = if (age < 18) "童年" else "成年" Java:(age<18)?"童年":"成年"
b、嵌套分支
在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层。 分支外面的分支结构称为外层分支。嵌套分支不要超过 3 层。
if(){
if(){
}else{
}
}
c、For循环控制
Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for 循环的特性被称 为 for 推导式或 for 表达式。
- 范围数据循环
for(i <- 1 to 3){ print(i + " ") } println()
;
-
i 表示循环的变量,<- 规定 to
-
i 将会从 1-3 循环,前后闭合
-
将to换成until,这种方式和前面的区别在于 i 是从 1 到 3-1,即使前闭合后开的范围
-
-
循环守卫
-
语法
for(i <- 1 to 3 if i != 2) { print(i + " ") } println()
;
-
循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环 体内部,为 false 则跳过,类似于 continue。
-
上面等价于
for (i <- 1 to 3){ if (i != 2) { print(i + " ") } }
;
-
-
循环步长
-
for (i <- 1 to 10 by 2) { println("i=" + i) }
by后面的数字表示步长
-
-
嵌套循环
-
语法
for(i <- 1 to 3; j <- 1 to 3) { println(" i =" + i + " j = " + j) }
注意:没有关键字,所以范围后一定要加;来隔断逻辑
-
与上面的代码等价
for (i <- 1 to 3) { for (j <- 1 to 3) { println("i =" + i + " j=" + j) } }
;
-
-
引入变量
-
语法
for(i <- 1 to 3; j = 4 - i) { println("i=" + i + " j=" + j) }
注意:
-
for 推导式一行中有多个表达式时,所以要加 ; 来隔断逻辑
-
for 推导式有一个不成文的约定:当 for 推导式仅包含单一表达式时使用圆括号, 当包含多个表达式时,一般每行一个表达式,并用花括号代替圆括号,如下
for { i <- 1 to 3 j = 4 - i } { println("i=" + i + " j=" + j) }
;
-
-
-
循环返回值
-
语法
val res = for(i <- 1 to 10) yield i println(res)
说明:将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字。 注意:开发中很少使用。
-
-
倒序打印
-
如果想倒序打印一组数据,可以用 reverse。
-
-
列:
for(i <- 1 to 10 reverse){ println(i) }
;
d、While和do..While循环控制
- 基本语法
循环变量初始化 while (循环条件) { 循环体(语句) 循环变量迭代 }
;
-
循环条件是返回一个布尔值的表达式
-
while 循环是先判断再执行语句
-
与 for 语句不同,while 语句没有返回值,即整个 while 语句的结果是 Unit 类型()
-
因为 while 中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免的使用变量,而变量需要声明在 while 循环的外部,那么就等同于循环的内部对外部的变量 造成了影响,所以不推荐使用,而是推荐使用 for 循环。
-
--------------------
-
do..while 循环控制
-
基本语法
循环变量初始化; do{ 循环体(语句) 循环变量迭代 } while(循环条件)
;
-
循环条件是返回一个布尔值的表达式
-
do..while 循环是先执行,再判断
while和do..while和java中用法类似
e、循环中断
- 基本说明
Scala 内置控制结构特地去掉了 break 和 continue,是为了更好的适应函数式编程,推 荐使用函数式的风格解决break和continue的功能,而不是一个关键字。Scala中使用breakable 控制结构来实现 break 和 continue 功能。 ;
-
需求 1:采用异常的方式退出循环
def main(args: Array[String]): Unit = { try { for (elem <- 1 to 10) { println(elem) if (elem == 5) throw new RuntimeException } }catch { case e => } println("正常结束循环") }
需求 2:采用 Scala 自带的函数,退出循环
import scala.util.control.Breaks def main(args: Array[String]): Unit = { Breaks.breakable( for (elem <- 1 to 10) { println(elem) if (elem == 5) Breaks.break() } ) println("正常结束循环") }
需求 3:对 break 进行省略
import scala.util.control.Breaks._ object TestBreak { def main(args: Array[String]): Unit = { breakable { for (elem <- 1 to 10) { println(elem) if (elem == 5) break } } println("正常结束循环") } }
需求 4:循环遍历 10 以内的所有数据,奇数打印,偶数跳过(continue)
object TestBreak { def main(args: Array[String]): Unit = { for (elem <- 1 to 10) { if (elem % 2 == 1) { println(elem) } else { println("continue") } } } }
;
f、多重循环
基本说明
- 将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for,while,do…while 均可以作为外层循环和内层循环。【建议一般使用两层,最多不要超过 3 层】
- 设外层循环次数为 m 次,内层为 n 次,则内层循环体实际上需要执行 m*n 次。