scala基础篇

1、基础语法

  • 基本概念
    • 对象:类的一个具体实例,对象包含属性和方法,如旺财有属性毛色和看家本领能力。
    • 类:类是对象的抽象,对象是类的一个实例。
    • 方法:描述类所拥有的行为能力,一个类可以拥有多个方法。
    • 属性:也称字段,即每个对象拥有它自身实例变量集合,通过赋值来创建真正的属性值。
  • 基本语法
    • 区分大小写
    • 类名:首字母要大写,如class HelloWorld{},class Person{},class Student{},也称大驼峰
    • 方法名称:首字母小写,从第2个单词开启的首字段大写,如def toString(),def getName(),即为小驼峰
    • 程序文件名:保持与类名或对象名一致,区分大小写,以”.scala”来结尾,规范上是如上要求,实际是可以不对应的。
    • 主程序入口:def main(args: Array[String]) ,scala若要独立运行必须从Object的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;
    • 引入包下所有类:import java.util._;
    • 引入包下若干类(选择器):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

  • 数据类型的关系图

2 scala基础篇 - 图1

  • 常见字面量
    • 整型字面量:如:0,1,0xff,07L
    • 浮点型字面量:0.0,3.14159f
    • 布尔型字面量:true 或者 false
    • 字符字面量:单引号括起来,如’a’,’b’,’\t’
    • 字符串字面量:双引号括起来,如”HelloWorld”,”MyName”
    • Null值:是对引用对象类型的子类,不兼容值类型。

3、变量

  • 常量
    • 在程序运行过程中其值不会发生变化的量叫做常量。如:”A”、”B”、”123”太丰富
    • 使用val来声明常量

val constString:String=”hero”;
val constString=”new_hero”;

  • 变量
    • 在程序运行过程中其值可能发生改变的量叫做变量。如:对象的名称、年龄、发色、身材等
    • 使用var来声明变量

var varString:String=”name”;
var 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
      • 仅在包含了成员定义的类或对象内部可见
      • 在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员。

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 SubStudent {
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 |

  • 位运算符

    • 常用位运算

用来对二进制位进行操作,~,&,|,^分别为取反,按位与与,按位与或,按位与异或运算

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;
//注意:begin++在此处不可用
}
}
}

  • 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(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…
} yield x
注意大括号中用于保存变量和条件,retValList 是变量, 循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。
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。
    • scala当中的返回值在返回时,可以用return,也可不用,如果不用return即代表方法的最后一个变量即为返回值。
    • 参数列表中的参数可以使用逗号分隔。
      • 经典示例
  • 无返回值方法定义

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);
}
}

  • 函数的高级编程写法(在进阶篇中讲解)
    • 函数传名调用
    • 指定函数参数名调用
    • 可变参数的函数
    • 默认参数值函数
    • 递归函数
    • 高阶函数
    • 内嵌函数
    • 匿名函数
    • 偏应用函数
    • 函数柯里化等

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对等
  • 使用示例
    • 不可变字符串创建

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:

      1. ![](https://cdn.nlark.com/yuque/0/2021/jpeg/21891685/1630501638342-22e7de9c-7fe8-45a8-9581-c9d59e5ac92c.jpeg#)
  • 数组定义

    • 静态数组

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 ArrayString
// var programLanguageArray:Array[String] = new ArrayString
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 ArrayString
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 = ofDimInt
// 创建二维方阵
for (i <- 0 to myMatrix.length - 1) {
for (j <- 0 to myMatrix(i).length - 1) {
myMatrix(i)(j) = (i + 1) * (j + 1);
}
}

// 输出二维方阵
for (i <- 0 to myMatrix.length - 1) {
for (j <- 0 to myMatrix(i).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(start,end,step) 方法来生成一个区间范围内的数组
      • range(start,end,step) 方法最后一个参数为步长,默认为 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)
}
}
}
11、练习题

  • 给定一个整型数组arr,实现对该数组的冒泡排序?
  • 给定一个整型有序数组arr,实现对该数组的二分查找?
  • 给定一个任意整数m,实现对该整数求一阶阶乘?