1、基础语法
- 基本概念
- 对象:类的一个具体实例,对象包含属性和方法,如旺财有属性毛色和看家本领能力。
- 类:类是对象的抽象,对象是类的一个实例。
- 方法:描述类所拥有的行为能力,一个类可以拥有多个方法。
- 属性:也称字段,即每个对象拥有它自身实例变量集合,通过赋值来创建真正的属性值。
- 基本语法
- 区分大小写
- 类名:首字母要大写,如 class HelloWorld{},class Person{},class Student{},也称大驼峰
- 方法名称:首字母小写,从第 2 个单词开启的首字段大写,如def toString(),def getName(),即为小驼峰
- 程序文件名:保持与类名或对象名一致,区分大小写,以".scala"来结尾。
- 主程序入口:def main(args: Array[String]) ,scala 若要独立运行必须从 main 方法开始处理,每个 scala 强制程序入口。
- 标识符
- 兼容 java 标识符命名规范
- 命名规范:类为大驼峰,其它为小驼峰
- 多符号命名:可以加入“$,+,++,<“等符号参与命名,注意首字符和尾字符的若干限制,如"$"不要作为开头,"_"不要作为结 尾。
- 有新增关键字,如 yield 成为 scala 新关键字,则在 scala 调用时,则应由 Thread.yield()改成 Thread.`yield`来使用。
- 关键字
- 以下为保留关键字,不要以关键字作为变量命名。
abstract | case | catch | class |
def | do | else | extends |
false | final | finally | for |
forSome | if | implicit | import |
lazy | match | new | null |
object | override | package | private |
protected | return | sealed | super |
this | throw | trait | try |
true | type | val | var |
while | with | yield | |
- | : | = | => |
<- | <: | <% | >: |
# | @ |
- 注释
- 兼容 Java 注释,支持单行和多行
- 支持多行注释的嵌套结构
- 换行符
- 面向行编程的语言,每行语句可以用显式的";"来结尾,或者以回车换行来结尾。即末尾的";"是可选的。
- 如果一行中包括多个语句,则必须用";"来分隔。
- 包定义
- 兼容 java 包方式,如 package com.tl.utils;
- 类 c#的包定义方式
package com.tl.test {
class MyTest {
}
- 引用
- 引入单个类:import java.util.Date; o 引入包下所有类:import java.util._; o 引入包下若干类(选择器):import
java.util.{Date,HashSet,HashMap}
-
- 引入类后重命名:import java.util.{Date => OldDate}
- 隐藏包下的部分成员:import java.util.{Date=>_,_}
- 默认包引入为:java.lang._、scala._、Predef._,默认引入的包的情况下其内类的使用均不需要加上包名。
2、数据类型
- 与Java 相似部分(皆为对象类型,scala 无原生数据类型)
Byte,Short,Int,Long,Float,Double,Char,String,Boolean
- 差异部分
- Unit:即为空值或无值,与 Java 中的 void 等同。
- Null:即为 null,即空引用
- Nothing:是任何类型的子类型,在 scala 类层级的最末端
- Any:是所有其它类的基(父)类
- AnyRef:是所有引用类的基础,即除了值类型之外
- AnyVal:是所有值类型的基类,包括 9 个值类型
scala.Double scala.Float scala.Long scala.Int scala.Char scala.Short scala.Byte scala.Unit scala.Boolean |
- 常见变量
- 整型变量:如:0,1,0xff,07L
o 浮点型变量:0.0,3.14159f
- 布尔型变量:true 或者 false
- 字符变量:单引号括起来,如'a','b','\t'
- 字符串变量:双引号括起来,如"HelloWorld","MyName"
- Null 值:是对引用对象类型的子类,不兼容值类型。
3、变量
- 常量
- 在程序运行过程中其值不会发生变化的量叫做常量。如:"A"、"B"、"123"太丰富
- 使用 val 来声明常量
val constString:String="hero"; constString="new_hero"; |
- 变量
- 在程序运行过程中其值可能发生改变的量叫做变量。如:对象的名称、年龄、发色、身材等
- 使用 var 来声明变量
var varString:String="name"; varString="new_name"; |
- 变量类型声明
- 显式声明类型
var variableName : DataType [= Initial Value] 或 val constName: DataType [= Initial Value] |
- 隐式声明类型
var myString="HelloWorld"; var myInt=1; |
- 批量变量声明
var a,b=10; println(a+b); |
4、访问修饰符
- scala 访问修饰符包括 private,protected,public,对象的访问级别默认都是public
- private
- 仅在包含了成员定义的类或对象内部可见
- 在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员。
- private
class TestPrivate { class Person { private def testPrivate() { println("in private method"); } def testPublic() { println("in private method"); } class Student { testPrivate(); //正确 } } |
(new Person()).testPublic() //public 方法访问,正确 (new Person()).testPrivate() //private 方法访问,错误 } |
- protected
- 比 java 的 protected 更严格,除了子类可以访问,同包下的类是不能访问的
class TestProtected { class Animal { protected def walk() { println("i can walk!") } } class Person extends Animal { walk() //子父类继承的情况下,能访问proected 修饰的方法 } class Grass { (new Animal).walk() //同包下不能访问 proected 修饰的方法 } } |
- public
- 跟 Java 完全一致
- 作用域保护
- 通过 private[x]或 protected[x]来实现,可以修饰包、类、单例对象。
- private[x],即为"这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见外,对其它所有类都是 private。
- protected[x],即为"这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见外,对其它所有类都是 protected。
- 示例
class TestPrivate { class Student { private[TestPrivate] def testPrivate1() { println("in private method"); } private def testPrivate2() { println("in private method"); } def testPublic() { println("in private method"); } class Student { |
testPrivate1(); } } (new Student()).testPrivate1() //有[]作用域修饰,可以访问 (new Student()).testPrivate2() //没有[]作用域修饰,依然是不可以访问 } |
5、运算符
包括 5 种运算符,即算术运算符,关系运算符,逻辑运算符,位运算符,赋值运算符
- 算术运算符
运算符 | 描述 | 实例 |
+ | 加号 | A + B 运算结果为 30 |
- | 减号 | A - B 运算结果为 -10 |
* | 乘号 | A * B 运算结果为 200 |
/ | 除号 | B / A 运算结果为 2 |
% | 取余 | B % A 运算结果为 0 |
- 关系运算符
运算符 | 描述 | 实例 |
== | 等于 | (A == B) 运算结果为 false |
!= | 不等于 | (A != B) 运算结果为 true |
> | 大于 | (A > B) 运算结果为 false |
< | 小于 | (A < B) 运算结果为 true |
>= | 大于等于 | (A >= B) 运算结果为 false |
<= | 小于等于 | (A <= B) 运算结果为 true |
- 逻辑运算符
运算符 描述 实例 | ||
&& | 逻辑与 | (A && B) 运算结果为 false |
|| | 逻辑或 | (A || B) 运算结果为 true |
! | 逻辑非 | !(A && B) 运算结果为 true |
- 位运算符
o 常用位运算
用来对二进制位进行操作,~,&,|,^分别为取反,按位与与,按位与或,按位与异或运算
p | q | p & q | p | q | p ^ q |
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
- 全部位运算符
运算符 | 描述 | 实例 |
& | 按位与运算符 | (a & b) 输出结果 12 ,二进制解释: 0000 1100 |
| | 按位或运算符 | (a | b) 输出结果 61 ,二进制解释: 0011 1101 |
^ | 按位异或运算符 | (a ^ b) 输出结果 49 ,二进制解释: 0011 0001 |
~ | 按位取反运算符 | (~a ) 输出结果 -61 ,二进制解释: 1100 0011, 在一个 有符号二进制数的补码形式。 |
<< | 左移动运算符 | a << 2 输出结果 240 ,二进制解释: 1111 0000 |
>> | 右移动运算符 | a >> 2 输出结果 15 ,二进制解释: 0000 1111 |
>>> | 无符号右移 | A >>>2 输出结果 15, 二进制解释: 0000 1111 |
- 赋值运算符
运算符 | 描述 | 实例 |
= | 简单的赋值运算,指定右边操 作数赋值给左边的操作数。 | C = A + B 将 A + B 的运算结果 赋值给 C |
+= | 相加后再赋值,将左右两边的 操作数相加后再赋值给左边的操作数。 | C += A 相当于 C = C + A |
-= | 相减后再赋值,将左右两边的操作数相减后再赋值给左边的 操作数。 | C -= A 相当于 C = C - A |
*= | 相乘后再赋值,将左右两边的 操作数相乘后再赋值给左边的操作数。 | C *= A 相当于 C = C * A |
/= | 相除后再赋值,将左右两边的操作数相除后再赋值给左边的 操作数。 | C /= A 相当于 C = C / A |
%= | 求余后再赋值,将左右两边的 操作数求余后再赋值给左边的操作数。 | C %= A is equivalent to C = C % A |
<<= | 按位左移后再赋值 | C <<= 2 相当于 C = C << 2 |
>>= | 按位右移后再赋值 | C >>= 2 相当于 C = C >> 2 |
&= | 按位与运算后赋值 | C &= 2 相当于 C = C & 2 |
^= | 按位异或运算符后再赋值 | C ^= 2 相当于 C = C ^ 2 |
|= | 按位或运算后再赋值 | C |= 2 相当于 C = C | 2 |
- 运算符优先级
1 | () [] | 左到右 |
2 | ! ~ | 右到左 |
3 | * / % | 左到右 |
4 | + - | 左到右 |
5 | >> >>> << | 左到右 |
6 | > >= < <= | 左到右 |
7 | == != | 左到右 |
8 | & | 左到右 |
9 | ^ | 左到右 |
10 | | | 左到右 |
11 | && | 左到右 |
12 | || | 左到右 |
13 | = += -= *= /= %= >>= <<= &= ^= |= | 右到左 |
14 | , | 左到右 |
6、控制语句
- if...else
- if
object TestControlSentence {
def main(args: Array[String]): Unit = {
var age = 15;
if (age <= 18) {
println("未成年人");
}
}
}
- if...else
object TestControlSentence {
def main(args: Array[String]): Unit = {
var age = 15;
if (age <= 18) {
println("未成年人");
} else {
println("少年已成年了");
}
}
}
- 循环
-
- while
object TestControlSentence {
def main(args: Array[String]): Unit = {
var end = 10;
var begin = 0;
while (begin < end) {
println(begin);
begin = begin + 1;
}
}
}
- do...while
object TestControlSentence {
def main(args: Array[String]): Unit = {
var end = 10;
var begin = 0;
do {
println(begin);
begin = begin + 1;
} while (begin < end)
}
}
- for 循环
- for 形式定义
for( var x <- Range ){
statement(s);
以上语法中,Range 可以是一个数字区间表示 i to j ,或者 i until j。左箭头 <- 用于为变量 x 赋值。 |
}
- 使用 i to j
object TestControlSentence {
def main(args: Array[String]): Unit = {
var end = 10;
var begin = 0;
for(x <- begin to end){
println(x)
}
}
}
- 使用i until j
object TestControlSentence {
def main(args: Array[String]): Unit = {
var end = 10;
var begin = 0;
for(x <- begin until end){
println(x)
}
}
}
- 双变量循环
object TestControlSentence {
def main(args: Array[String]): Unit = {
var end = 5;
var begin = 1;
for(x <- begin to end;j <- begin to end){
println(x+"*"+j)
}
}
}
- 集合循环
object TestControlSentence {
def main(args: Array[String]): Unit = {
val stringList = List("one","two","three","four","five","six");
for(str <- stringList){
println(str)
}
}
}
- 循环中带过滤
object TestControlSentence {
def main(args: Array[String]): Unit = {
val stringList = List("one","two","three","four","five","six");
for(str <- stringList if(str!="two" && str!="three")){
println(str)
}
}
}
- for 循环加入yield 返回结果集合
- 定义形式
var retValList = for{ var x <- List
if condition1; if condition2...
注意大括号中用于保存变量和条件,retValList 是变量, 循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。 |
} yield x
object TestControlSentence {
def main(args: Array[String]): Unit = {
val stringList = List("one", "two", "three", "four", "five", "six");
var resultList = for {
str <- stringList if (str != "two" && str != "three")
} yield str;
for (temp <- resultList) {
println(temp)
}
}
}
7、方法与函数
- 两者的区分说明
- Scala 有方法与函数,二者在语义上的区别很小,在绝大多数情况下,两者是视为对等的。
- Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量,即在类中定义的函数即是方法。
- Scala 中的方法跟 Java 的类似,方法是组成类的一部分。
- Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。
- Scala 中使用 val 语句可以定义函数,def 语句定义方法。
- 方法定义
- 定义格式
def functionName ([参数列表]) : [return type] = {
function body
return [expr]
}
-
- 相关说明
- 如果不写等于号和方法主体,则方法会被隐式声明为"抽象方法",包含它的类型于是也是一个抽象类型。
- return type 可以是任意合法的 Scala 数据类型,如果函数没有返回值,可以返回为 Unit,这个类似于 Java 的 void
- 参数列表中的参数可以使用逗号分隔。
- 相关说明
- 经典示例
-
- 无返回值函数定义
object TestFunction {
def printMessage() : Unit = {
println("HelloWorld!")
}
}
-
- 加法定义
object TestFunction {
def printMessage(): Unit = {
println("HelloWorld!")
}
def add4Int(first: Int, second: Int): Int = {
var sum: Int = 0
sum = first + second
return sum
}
}
- 方法调用
- 调用说明
- 当不需要实例化对象时,functionName(参数列表)即可
- 当需要实实例化对象时,为 instance.functionName(参数列表)即可
- 示例 1-不需要实例化对象
- 调用说明
object TestFunction {
def printMessage(): Unit = {
println("HelloWorld!")
}
def add4Int(first: Int, second: Int): Int = {
var sum: Int = 0
sum = first + second
return sum
}
def main(args: Array[String]): Unit = {
printMessage();
var sum = add4Int(3, 4);
print("3+4 的和="+sum);
}
}
- 示例 2-需要实例化对象
object TestFunctionV2 {
class TestClassFunction {
def printMessage(): Unit = {
println("HelloWorld!")
}
def add4Int(first: Int, second: Int): Int = {
var sum: Int = 0
sum = first + second
return sum
}
}
def main(args: Array[String]): Unit = {
var classFunctionInstance = new TestClassFunction;
var sum = classFunctionInstance.add4Int(3, 4);
println("class 3+4 的和=" + sum);
}
}
- 函数的高级编程写法(在进阶篇中讲解)
- 函数传名调用
- 指定函数参数名调用
- 可变参数的函数 o 默认参数值函数o 递归函数
- 高阶函数 o 内嵌函数o 匿名函数
- 偏应用函数
- 函数柯里化等
8、闭包
- 闭包概念
- 闭包是个函数。
- 函数计算的过程,依赖于声明在函数外部的一个或多个变量。
- 闭包示例
object TestCloseFunction {
var factor = 1000
def salaryMoney(i: Int): Int = {
return i * factor
}
def main(args: Array[String]) {
println("月薪 salaryMoney(8) value = " + salaryMoney(8))
println("月薪 salaryMoney(10) value = " + salaryMoney(10))
TestCloseFunction.factor = 10000;
println("年薪 salaryMoney(8) value = " + salaryMoney(8))
println("年薪 salaryMoney(10) value = " + salaryMoney(10))
}
}
9、字符串
- 概念介绍
- 在 Scala 中,字符串的类型实际上是 Java String,它本身没有String 类。
- 完全与 java.lang.String 对等
- 使用示例
o 不可变字符串创建
object TestString {
var message = "过年好!";
var messageV2: String = "过年好!";
def main(args: Array[String]): Unit = {
println(message);
println(messageV2);
}
}
- 可变字符串创建(StringBuilder)
object TestStringBuilder {
def main(args: Array[String]) {
val stringBuilder = new StringBuilder;
stringBuilder += '1'
stringBuilder ++= "234"
stringBuilder.append("567")
stringBuilder.append('8')
println("stringBuilder is : " + stringBuilder.toString);
}
}
- 常用函数
- 求字符串长度 length 方法
def main(args: Array[String]) {
var str="12345678";
println("str length()="+str.length());
}
- 字符串连接concat 或是+符号
def main(args: Array[String]) {
var str = "12345678";
var str2 = "9";
println("str.concat(str2)=" + str.concat(str2));
println("str.concat(str2)=" + str + str2);
}
- 字符串格式化 printf
def main(args: Array[String]) {
var name = "天亮教育";
var location = "石家庄";
var work = "大数据技能培训";
var age=21;
printf("我是%s,我在%s,我做%s,我今年%d 岁了",name,location,work,age);
}
10、数组
- 概念说明
- 用来存储固定大小的同类型元素
- 元素是通过索引来访问的,第一个元素索引为 0,最后一个元素的索引为元素总数减 1
- 下图展示了一个长度为 10 的数组 myList,索引值为 0 到 9:
- 数组定义
- 静态数组
def main(args: Array[String]): Unit = {
var programLanguageArray = Array("java", "python", "c++", "c", "php")
for (program <- programLanguageArray) {
println(program);
}
}
- 动态数组
def main(args: Array[String]): Unit = {
var programLanguageArray = new Array[String](5)
// var programLanguageArray:Array[String] = new Array[String](5)
programLanguageArray(0) = "java";
programLanguageArray(1) = "python";
programLanguageArray(2) = "c++";
programLanguageArray(3) = "c";
programLanguageArray(4) = "php";
for (program <- programLanguageArray) {
println(program);
}
}
- 数组遍历操作
def main(args: Array[String]): Unit = {
var programLanguageArray = new Array[String](5)
programLanguageArray(0) = "java";
programLanguageArray(1) = "python";
programLanguageArray(2) = "c++";
programLanguageArray(3) = "c";
programLanguageArray(4) = "php";
println("加强 for 循环遍历");
for (program <- programLanguageArray) {
println(program);
}
println("数组下标循环遍历");
for (i <- 0 to (programLanguageArray.length - 1)) {
println(programLanguageArray(i))
}
}
多维数组概念
多维数组(>=2)即为数组的数组,与 Java 中概念等同
数组中的元素即可以是实体的值,也可以是一个数组,且可以嵌套
-
多数数组定义与应用import Array.ofDim;
object TestMultiArray{
def main(args: Array[String]): Unit = {
var myMatrix = ofDim[Int](4, 4)
// 创建二维方阵
for (i <- 0 to myMatrix.length - 1) {
for (j <- 0 to myMatrix.length - 1) {
myMatrix(i)(j) = (i + 1) * (j + 1);
}
}
// 输出二维方阵
for (i <- 0 to myMatrix.length - 1) {
for (j <- 0 to myMatrix.length - 1) {
print(" " + myMatrix(i)(j));
}
println();
}
}
}
- 数组合并
import Array.concat; |
object TestArray {def main(args: Array[String]): Unit = {
var numberList1 = Array(1, 2, 3, 4)
var numberList2 = Array(5, 6, 7, 8)
var mergeList = concat(numberList1, numberList2)
// 输🎧所有数组元素
for (x <- mergeList) {
println(x)
}
}
}
- 创建区间数组
- 区间数组说明
- range() 方法来生成一个区间范围内的数组
- range() 方法最后一个参数为步长,默认为 1
- 是半包区间,包含起始值,不包括结束值,即start<=x<end
-
import Array.range;
示例应用
- 区间数组说明
object TestArrayRange {
def main(args: Array[String]): Unit = {
var numberList1 = range(1, 5, 2)
var numberList2 = range(1, 5)println("手动设置步长为 2")
// 输入所有数组元素-numberList1
for (x <- numberList1) {
println(x)
}
println("采用默认步长值,即为 1")
// 输出所有数组元素-numberList2
for (x <- numberList2) {
println(x)
}
}
}