文章目录
1. 变量和数据类型
1.1 变量和常量
-
语法
- 定义变量:
var 变量名:数据类型 = 值
【相当于Java 没有 用final
关键字修饰】 - 定义常量:
val 常量名:数据类型 = 值
【相当于Java 用final
关键字修饰】- 建议:能用常量,就不要用变量
- 变量名命名规范:
- 定义变量:
-
多变量声明
// 1. 数值 val (a,b,c) = (1,2,4) println(a) //1 println(b) //2 println(c) //4 // 2. 集合:常用于main方法取args参数,比如 val Array(input, output) = args val Array(a, b, c) = Array(1, 2, 3) println(a) //1 println(b) //2 println(c) //3
-
注意点
// 1. 常量值无法修改 val NAME:String = "张三" NAME = "李四” // 报错 // 2. Scala是强引用,因此不可为变量赋不同数据类型的值 var age:int = 18 age = "张三" // 不可将字符串赋值给整型变量 // 3. 声明 常量、变量时,数据类型可以省略,但是初始值不可省略。这样可以自动推断数据类型 // 值为整型:Int // 值为小数:Double // 值为布尔:Boolean // 值为字符:Char // 值为字符串:String // 值为():Unit val NAME = "张三" // 会自动推断变量类型,这里会推断为字符串类型 // 4. 关于对象: // (1) var修饰的对象可以修改指向,而val修饰的对象不可以修改修改指向 // (2) 对象的属性是否可以修改,取决于属性是用var还是val修饰 val PERSON = Person() PERSON = Person() // 错误
1.2 字符串
-
字符串拼接
-
通过
+
号连接# 方式一: println("hello" + "world") # 方式 而: print("hello".concat("world"))
-
重复字符串拼接
println("linhailinhai" * 200)
-
-
字符串输出
- 通过
%
+format / printf
传值:和c语言一样var name = "张三" var age = 18 // print()不换行,println()换行 printf("name: %s age: %d\n", name, age) printf("name: %s age: %d\n".format(name, age))
能够实现前缀填充:%s表示字符串,16表示最终的字符串长度,0表示不足的部分使用0填充,而%是格式说明符的开始。请注意,这两种方法都不会改变原字符串的值,而是返回一个新的字符串。
val s = "123" val result = "%016s".format(s) println(result) // 输出:0000000000000123
s
打头,然后通过${变量名}
获取变量值,和shell脚本一样。
如果只显示一个变量,var name = "张三" var age = 18 printf(s"name: ${name} age: ${age}\n")
{}
可以省略,如果有多个变量在{}
进行运算,则不可省略:var name = "张三" var age = 18 printf(s"name: $name\n") // ${name} 可以省略花括号 printf(s"name: ${name + age}\n") // 此时,花括号不可省略
- 通过
-
三引号字符串:方便写SQL
// s打头,每个行用 | ,最后.stripMargin val sql = s""" | select * | from table | where name = ${name} | and age > ${num} """.stripMargin // stripMargin 的作用就是忽略前后空格、以及中间的|等符号,也就是说只剩下SQL语句
-
关于字符串中的转义:
\n
在字符串中代表着换行,如果想要字符串中显示\n
,着需要转移一下,即\\n
。适用于双引号和三引号。- 使用双引号和三引号时,即
"xx"
和"""xxx"""
,边界是双引号。如果字符串中要出现"
,则只能使用三引号+转义。"""xx\\"x"""
// 例子: val str = s"""${event_day}的结算侧【补贴分润】数据存在<font color=\\"red\\">**异常**</font>,可能存在的问题:\\n > ①会员ID等字段异常 <= 0; \\n > ②补贴数据的会员id和cpuuser的会员id对不上 \\n\\n 需要评估是否正常。这些用户的【预计补贴】总金额为 ${row.getAs(0)}, 【实际补贴】总金额为 ${row.getAs(1)}。\\n AFS数据地址:${check_result_fail_afs_path_data_side.format(event_day)}""".stripMargin
1.3 数据类型
Scala中没有基本数据类型,只有引用数据类型:分为 基本引用数据类型 和 非基本引用数据类型两类
- 基本引用数据类型包含
(Byte, Short, Char, Integer❌ Int✅, Long, Float, Double, Boolean)
+Unit
Unit 相当于 Java中的 void,在这里属于基本数据类型,其只有一个值,即
()
。比如val a = ()
此时,a为Unit
类型。 - 非基本引用数据类型:基本引用数据类型之外的属于非基本引用数据类型,比如String
- 重要父类 / 子类:
Any
类,是所有类的父类,等价于Java的ObjectAnyVal
类是所有基本引用数据类型的父类AnyRef
类是所有非基本引用数据类型的父类。Nothing
是所有引用数据类型的子类。应用场景:一个函数没有明确返回值时指定
- 引用类型关系图:
细节:
- 引用数据类型的默认值:
- 9种基本引用数据类型:
- Byte、Short、Int、Float、Double默认值都是
0
- Char默认值是
\u0000
object Test { var c:Char = _ def main(args: Array[String]): Unit = { println(this.c) // 输出:'\u0000' } }
- 布尔类型默认值是
false
- Unit默认值是
()
- 非基本引用数据类型:null
- 只有基本引用数据类型部分可以不写数据类型,自动推断类型。而引用数据类型必须指定数据类型,否则会报错。
- 字符串默认是
String
。比如:val name = "zhangsan"
- 整数默认是
Int
。比如:val age = 15
- 整数+L 默认是
Long
。比如val age = 15L
- 小数默认是
Double
。比如:val money = 150.0
- 小数 + F 默认是
Fl0at
。比如:val money = 150.0F
- 字符默认是
Char
。比如:val c = 'x'
- 布尔默认是
Boolean
。比如:val is_find = false
()
默认是Unit
。比如:val a = ()
Byte
和Short
无法进行自动推断,必须指名数据类型。比如val a:Byte = 1
- 引用数据类型必须指定数据类型。比如:
val person:Person = null
- Nothing vs Unit vs Null
Unit
用于方法无返回值的情况Nothing
用于非方法的代码块无返回值的情况Null
是非基本引用对象没有赋值的默认值
- 集合类型的泛型很容易和Java中的数组弄混:
- Java中用
<>
表示泛型,[]
用来定义数组:int[] a = {0, 1, 2}; Array<String> = new Array("aaa", "bbb", "ccc")
- Scala中用
[]
泛型:Array[Int] a = Array(0, 1, 2) // 使用伴生对象创建数组
// 访问`Array`: val arr = new Array(10, 20, 30) println(arr(0)) // 输出第一个元素10
1.4 代码块
在Scala中:
- 所有代码都是代码块
- 最后一行代码的结果就是返回值
- 函数无返回值可用
Unit
- 代码块无返回值可用
Nothing
- 函数无返回值可用
object Test {
def main(args: Array[String]): Unit = {
// 所有的代码都是代码块
// 表示运行一段代码 同时将最后一行的结果作为返回值
val i: Int = {
println("我是代码块")
10 + 10
}
// 代码块为1行的时候 大括号可以省略
val i1: Int = 10 + 10
// 如果代码块没有计算结果 返回类型是unit
val unit: Unit = {
println("hello")
println("我是代码块")
}
// 当代码块没办法完成计算的时候 返回值类型为nothing
// val value: Nothing = {
// println("hello")
// throw new RuntimeException
// }
}
}
1.5 强制转换
调用方法进行强制转换:
// Java :
// (1) 基本数据类型的强制转换
int num = (int)2.5
// (2) 引用数据类型的强制转换只发生在父子类之间
Animal animal = new Animal();
if(animal instanceof Dog) {
Dog dog = (Dog) animal;
}
// Scala :
// (1) AnyVal的使用to方法
// 1)对象.to方法
val num : Int = "123".toInt // 这个转换会不安全,转换失败时会造成程序中断。
val num:Int = Try("123".toInt).getOrElse(0) // 转换失败时可以设置指定值,程序能继续运行
// 2) to方法(对象, 默认值)
val num : Int = toInt("123", 0)
// (2) 不能使用to方法的,用asInstanceOf强转
val a:Any = Person()
a.asInstanceOf[Person]
1.6 运算符
- 没有
++
、--
运算符 - 在Scala中,所有的运算符都是方法。
// 两者等价 val a = 10 + 5 val b = 10.+(5) println(a, b) // 输出:(15, 15)
1.7 == 与 equals
- Scala中
==
与equals
相同,都是比较两个对象的引用是否是同一个对象。Java的
==
用于比较地址是否相等;equals
用于比较内容是否相等。 - 如果要比较地址是否相同,用
.eq()
方法val s1 = "abc" val s2 = new String("abc") println(s1 == s2) println(s1.eq(s2)) // 输出结果: true false
- 如果要比较内容是否相等使用
sameElements
val arr1 = Array(1, 2, 3) val arr2 = Array(1, 2, 3) if (arr1 sameElements arr2) { println("The arrays are equal.") } else { println("The arrays are not equal.") }
2. 控制语句
2.1 分支语句
在Scala中,有if、if-else、if-else if-else,用法和Java一样。没有三元运算符、switch。
// 1. 没有三元运算符,但是可以用 if语句等价替换。
val a = if(10 > 1) 100 else 50
// 2. 没有swith,但是可以使用模式匹配等价替换,后面详细介绍
2.2 循环语句
(1)for循环
-
只有for-each循环,没有递增for循环:
// 1. 左闭右闭 [] for(i <- 1 to 10) { } // 2. 左闭右开 [) for(i <- 1 until 10) { } // 3. 循环步长 for(i <- 1 to 10 by 2) { // 步长为2,故结果为:1 3 5 7 9 } // 4. 遍历集合 for(i <- 集合对象){ }
注意:在方法体内不能修改
i
的值,会报错。 -
循环守卫
for(i <- 1 to 10 if i != 5) { // 排除5 }
-
一个for循环内定义多个变量
for(i <- 1 to 4; j <- 1 to 5) { println(s"i = $i, j = $j") } // 输出: i = 1, j = 1 i = 1, j = 2 i = 1, j = 3 i = 1, j = 4 i = 1, j = 5 i = 2, j = 1 i = 2, j = 2 i = 2, j = 3 i = 2, j = 4 i = 2, j = 5 i = 3, j = 1 i = 3, j = 2 i = 3, j = 3 i = 3, j = 4 i = 3, j = 5 i = 4, j = 1 i = 4, j = 2 i = 4, j = 3 i = 4, j = 4 i = 4, j = 5
(2)while/do-while循环
可以,前者是现在判断后执行;后者是先执行后判断。使用语法和Java一样,但是不推荐使用,推荐后面使用函数式编程的递归方法
(3)循环中断
Scala内置控制结构特地去掉了break和continue,是为了更好的适应 函数式编程,推荐使用函数式的风格解决break和continue的功能,而不是一个关键字,而是通过对象来中断。
// 使用Breaks.breakable()方法来实现中断
// 使用Breaks.break()方法代替java中的break关键字
Breaks.breakable(
for(i <- 1 to 10) {
if(i == 3)
Breaks.break() -- 写就是中断,不写就是continue
}
)
(4)yield关键字结合for循环使用
yield 的作用是把每次迭代生成的值封装到一个集合中,如果把yield去掉那返回给C的值就为Unit。
2.3 模式匹配
Scala的模式匹配和Java的switch语法很类型。常用来代替分支语句。
-
Java的switch语法
// expression可以是表达式,也可以是变量 switch(expression) { case value1: // 代码块1 break; case value2: // 代码块2 break; // 可以有任意数量的case语句 default: // 当所有case都不匹配时,执行此代码块 }
-
switch
用模式匹配match
代替:object TestMatchCase { def main(args: Array[String]): Unit = { var a: Int = 10 var b: Int = 20 var operator: Char = 'd' var result = operator match { case '+' => a + b case '-' => a - b case '*' => a * b case '/' => a / b case _ => "illegal" } println(result) } }
注意:在调用算子时,可以在里面直接写模式匹配。比如:
(1) 匹配变量
object Test02_MatchValue {
def main(args: Array[String]): Unit = {
// 匹配类型
def func2(x:Any):String ={
x match {
case i:Int => "整数"
case c:Char => "字符"
case s:String => "字符串"
case _ => "其他"
}
}
println(func2(1515))
println(func2('\t'))
println(func2("1515"))
}
}
(2) 匹配元组
object TestMatchTuple {
def main(args: Array[String]): Unit = {
//对一个元组集合进行遍历
for (tuple <- Array((0, 1), (1, 0), (1, 1), (1, 0, 2))) {
val result = tuple match {
case (0, _) => "0 ..." //是第一个元素是0的元组
case (y, 0) => "" + y + "0" // 匹配后一个元素是0的对偶元组
case (a, b) => "" + a + " " + b
case _ => "something else" //默认
}
println(result)
}
}
}
(3) 匹配对象及样例类
object Test05_MatchObject {
def main(args: Array[String]): Unit = {
val zhangsan = new Person05("zhangsan", 18)
zhangsan match {
case Person05("zhangsan",18) => println("找到张三啦")
case _ => println("你不是zhangsan")
}
}
}
class Person05 (val name:String,var age:Int){
}
object Person05{
// 创建对象的方法
def apply(name: String, age: Int): Person05 = new Person05(name, age)
// 解析对象的方法
def unapply(arg: Person05): Option[(String, Int)] = {
// 如果解析的参数为null
if (arg == null ) None else Some((arg.name,arg.age))
}
}
3. 简写
- 代码块只有一行时,可以省略
{}
。 - 形参和实参没有参数时,小括号
()
可以省略。
比如:
object Main {
def main(args: Array[String]): Unit = {
def hello():Unit = {
println("hello")
}
hello()
}
}
可简化为:
object Main {
def main(args: Array[String]): Unit = {
def hello:Unit = println("hello")
hello
}
}