Scala语法教程

article/2025/10/14 14:00:14

第一章 Scala入门

1.1概述

Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的 静态类型编程语言(静态语言需要提前编译的如:Java、c、c++等,动态语言如:js)。

1) Scala是一门多范式的编程语言,Scala支持面向对象和函数式编程。(多范式,就是多种编程方

法的意思。有面向过程、面向对象、泛型、函数式四种程序设计方法。)

2) Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有 的Java类库,实现两种语言的无缝对接。

3)Scala单作为一门语言来看,非常的简洁高效。

4)Scala在设计时,马丁·奥德斯基是参考了Java的设计思想,可以说Scala是源于Java,同时马丁·奥 德斯基也加入了自己的思想,将函数式编程语言的特点融合到JAVA中, 因此,对于学习过Java的同学, 只要在学习Scala的过程中,搞清楚Scala和Java相同点和不同点,就可以快速的掌握Scala这门语言。

1.2环境搭建

基于JDK1.8

下载scala2.12.11

配置scala环境变量

img

1.3代码编写(编译原理)

package chapter01class Student(name:String,info: Int) {def printInfo():Unit ={println(name+" "+info+" "+Student.school)}
}object Student{val school:String = "河北农业大学"
//伴生对象def main(args: Array[String]): Unit = {val student = new Student("张三",20)student.printInfo()}
}

编译后生成的class
Student$.class

package chapter01;public final class Student$
{public static  MODULE$;private final String school;static{new ();}public String school(){return this.school;}public void main(String[] args) {Student student = new Student("张三", 20);student.printInfo();}private Student$() {MODULE$ = this;this.school = "河北农业大学";}
}

Student.java

package chapter01;import scala.Predef.;
import scala.reflect.ScalaSignature;@ScalaSignature(bytes="\006\001}2Aa\003\007\001\037!Aa\003\001B\001B\003%q\003\003\005#\001\t\005\t\025!\003$\021\0251\003\001\"\001(\021\025a\003\001\"\001.\017\025\tD\002#\0013\r\025YA\002#\0014\021\0251c\001\"\0015\021\035)dA1A\005\002YBaa\016\004!\002\0239\002\"\002\035\007\t\003I$aB*uk\022,g\016\036\006\002\033\005I1\r[1qi\026\024\b'M\002\001'\t\001\001\003\005\002\022)5\t!CC\001\024\003\025\0318-\0317b\023\t)\"C\001\004B]f\024VMZ\001\005]\006lW\r\005\002\031?9\021\021$\b\t\0035Ii\021a\007\006\00399\ta\001\020:p_Rt\024B\001\020\023\003\031\001&/\0323fM&\021\001%\t\002\007'R\024\030N\\4\013\005y\021\022\001B5oM>\004\"!\005\023\n\005\025\022\"aA%oi\0061A(\0338jiz\"2\001\013\026,!\tI\003!D\001\r\021\02512\0011\001\030\021\025\0213\0011\001$\003%\001(/\0338u\023:4w\016F\001/!\t\tr&\003\0021%\t!QK\\5u\003\035\031F/\0363f]R\004\"!\013\004\024\005\031\001B#\001\032\002\rM\034\007n\\8m+\0059\022aB:dQ>|G\016I\001\005[\006Lg\016\006\002/u!)1H\003a\001y\005!\021M]4t!\r\tRhF\005\003}I\021Q!\021:sCf\004")
public class Student
{private final String name;private final int info;public static void main(String[] paramArrayOfString){Student..MODULE$.main(paramArrayOfString);}public static String school(){return Student..MODULE$.school();}public void printInfo(){Predef..MODULE$.println(2 + this.name + " " + this.info + " " + Student..MODULE$.school());}public Student(String name, int info){}
}

第二章 变量和数据类型

2.1 变量和常量

var 变量名 :变量类型 = 值

val 常量名 :常量类型 = 值

变量类型都可省略,编译器会自动推断

能使用常量的地方不用变量

(1) 声明变量时,类型可以省略

(2) 类型确定后不可以修改

(3) 变量声明时,必须有初始值

(4) 声明变量时,可以使用var和val,var可以变,val不可变

2.2 标识符的规范

以操作符开头,且只包含操作符(+ - * / # !等)

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

• package, import, class, object, trait, extends, with, type, for • private, protected, abstract, sealed, final, implicit, lazy, override

• try, catch, finally, throw

• if, else, match, case, do, while, for, return, yield

• def, val, var

• this, super • new • true, false, null

2.3 字符串

(1)字符串,通过+号连接 ,可以字符串乘法

(2)printf 用法:字符串,通过%传值。

(3)字符串模板(插值字符串):通过$获取变量值

var age="hello"
println(s"${age}")var num = 2.3456
println(f"The num is ${num}%.2f")//保留两位小数
println(raw"The num is ${num}%.2f")//raw 输出原格式//三引号格式 可以换行写多行文本,保持原格式
s"""""".stripMargin 

2.4 键盘输入

StdIn 就是new Scanner

基本语法

StdIn.readLine()、StdIn.readShort()、StdIn.readDouble()

2.5 文件操作

 def main(args: Array[String]): Unit = {//读取文件Source.fromFile("src/main/resources/test.txt").foreach(print)//将数据写入文件 scala没有封装好的写入文件类库 使用Java io即可val writer = new PrintWriter(new File("src/main/resources/test1.txt"))writer.write("hello scala from java writer")writer.close()}

2.6 数据类型

1)Scala中一切数据都是对象,都是Any的子类。

2)Scala中数据类型分为两大类:数值类型(AnyVal)、 引用类型(AnyRef),不管是值类型还是引用类型都是对象。

3)Scala数据类型仍然遵守,低精度的值类型向高精度值类型,自动转换(隐式转换)

4)Scala中的StringOps是对Java中的String增强

5) Unit:对应Java中的void,用于方法返回值的位置,表 示方法没有返回值。Unit是一个数据类型,只有一个对象 就是()。Void不是数据类型,只是一个关键字

6) Null是一个类型,只有一个对象就是null。它是所有引用类型(AnyRef)的子类。

Nothing,是所有数据类型的子类,主要用在一个函数没有明确返回值时使 用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数

img

img

第三章 流程控制

3.1 if else

语法与java没有区别

但每个分支都可以返回值

返回的类型为分支代码块的最后一行内容

val age = StdIn.readInt()var result = if (age>18){println("18")15} else{"000"}println(result)

3.2 for

to unitl

区别就在于until没有右边界

for(i <- 1 to 3){print(i + " ")
}
println()
------------------------------------------------------
for(i <- 1.to(3){print(i + " ")
}

底层是调用的方法

for (i <- Range(1,10)){}
//不包含边界 Range为伴生对象for (i <- 1 until 10){}
//底层就是上面

scala中的foreach循环

for (i <- Array(10,20,30))
for (i <- List(10,20,30))
for (i <- Set(10,20,30))

循环守卫

scala中没有continue

for (i <- 0 to 10 if i!=5){}

循环步长

for(i <- 1 to 3 by 2){}
//步长不能为0

反转 reverse

for(i <- 1 to 3 reverse){}
for(i <- 3 to 1 by -1){}

循环嵌套

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

循环返回值

很少用

object TestFor {def main(args: Array[String]): Unit = {var res = for(i <-1 to 10) yield {i * 2}println(res)}
}
输出结果:
Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

3.3 while do

因为 while 中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免 的使用变量,而变量需要声明在 while 循环的外部,那么就等同于循环的内部对外部的变量 造成了影响,所以不推荐使用,而是推荐使用 for 循环。

与java语法相同

3.4 循环中断

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

import scala.util.control.Breaks
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()//break()})println("正常结束循环")
}

第四章 函数式编程

img

4.1 函数和方法的区别

1)核心概念

(1)为完成某一功能的程序语句的集合,称为函数。

(2)类中的函数称之方法。

2)案例实操

(1)Scala 语言可以在任何的语法结构中声明任何的语法

(2)函数没有重载和重写的概念;方法可以进行重载和重写

(3)Scala 中函数可以嵌套定义

4.2 函数参数

(1)可变参数

(2)如果参数列表中存在多个参数,那么可变参数一般放置在最后

(3)参数默认值,一般将有默认值的参数放置在参数列表的后面

(4)带名参数

可变类似于python

def hello (*str):print(type(str))
hello("sac","1")
------------------------
<class 'tuple'>
def hello(string: String*)={println(string)}println(hello("1","2"))
----------------------------
WrappedArray(1, 2)

默认值

def hello(string: String = "hello")={println(string)}

带名参数

def hello(name,age)={println(name+age)
}
hello(age=15,name="张三")

4.3 函数至简原则(重点)

函数至简原则:能省则省

(1)return 可以省略,Scala 会使用函数体的最后一行代码作为返回值

(2)如果函数体只有一行代码,可以省略花括号

(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)

(4)如果有 return,则不能省略返回值类型,必须指定

(5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用

(6)Scala 如果期望是无返回值类型,可以省略等号

(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加

(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略

(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略

匿名函数 lambda表达式

4.4 匿名函数

没有名字的函数就是匿名函数。

(x:Int)=>{函数体}

def fun1(name:String): Unit ={println(name)}val tmp = (name:String)=>{println(name)}def fun2(fun:String => Unit): Unit ={fun("张三")}fun2(tmp)

(1)参数的类型可以省略,会根据形参进行自动的推导

fun2((name)=>{println(name)})

(2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参 数超过 1 的永远不能省略圆括号。

fun2( name =>{println(name)})

(3)匿名函数如果只有一行,则大括号也可以省略

fun2( name => println(name))

(4)如果参数只出现一次,则参数省略且后面参数可以用_代替

x fun2( name => println(_))
fun2( println(_))

离谱版

fun2(println)

4.5 函数高级

函数对象

def fun1(name:String): Unit ={println(name)
}
val tmp = (name:String)=>{println(name)}
def fun2(fun:String => Unit): Unit ={fun("张三")
}
val f1 = fun2 _
val f2: String => Unit= fun1

val f1 = fun2 _

也可以返回一个函数对象

函数赋值

def func1(s:String): Char=>(Int=>Boolean)={def func2(c:Char): Int=>Boolean ={def fun3(i:Int):Boolean ={if(i==0&&c=='0'&&s=='0') true else false}fun3}func2}

函数柯里化

def func1(i:Int)(s:String)(c:Char):Boolean={true
}

4.6 闭包

闭包:函数式编程的标配

闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的 环境,称为闭包

def func1(s:String): Char=>(Int=>Boolean)={def func2(c:Char): Int=>Boolean ={def fun3(i:Int):Boolean ={if(i==0&&c=='0'&&s=='0') true else false}fun3}func2}

当函数func1调用后弹出栈局部变量也会被释放,但fun3仍然可以访问到上层函数的局部变量

这是因为scala将局部变量创建了函数对象打成了包放在了堆内存里,

4.7 递归

def con(n:Int): Int = {if (n ==0) return 1con(n-1) * n}
//尾递归,节省栈空间,指针不用变化
def con1(n:Int):Int = {@tailrec //该注解可检查尾递归是否正确def loo(n:Int,sum:Int):Int = {if(n==0) return sumloo(n-1,sum * n)}loo(n,1)
}

4.8 控制抽象

1)值调用:把计算后的值传递过去

 object TestControl {def main(args: Array[String]): Unit = {def f = ()=>{println("f...")10}foo(f())}def foo(a: Int):Unit = {println(a)println(a)}
}

2)名调用:把代码传递过去

object TestControl {def main(args: Array[String]): Unit = {def f = ()=>{println("f...")10}foo(f())}
//def foo(a: Int):Unit = {def foo(a: =>Int):Unit = {//注意这里变量 a 没有小括号了println(a)println(a)}
}
输出结果:
f...
10
f...
10 

自己定义while循环

def myWhile(flag: => Boolean): (=> Unit)=>Unit= {def dowhile(con: => Unit):Unit = {conif (flag)dowhile(con)}dowhile}var n=10myWhile(n>=1){println(n)n-=1}}

4.9 懒加载

当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函 数才会执行。这种函数我们称之为惰性函数。

第 五 章 面向对象

5.1包说明(包语句)

Scala 有两种包的管理风格,一种方式和 Java 的包管理风格相同,每个源文件一个包(包 名和源文件所在路径不要求必须一致),包名用“.”进行分隔以表示包的层级关系,如 com.atguigu.scala。另一种风格,通过嵌套的风格表示层级关系,如下

package com{
package atguigu{
package scala{
}
}
}

第二种风格有以下特点:

(1)一个源文件中可以声明多个 package

(2)子包中的类可以直接访问父包中的内容,而无需导包

5.2 包对象

Scala 中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对 应包下所有 class 和 object 的共享变量,可以被直接访问。

package object com{
val shareValue="share"
def shareMethod()={}
}

如采用嵌套方式管理包,则包对象可与包定义在同一文件中,但是要保证包对象 与包声明在同一作用域中。

5.3 导包说明

1)和 Java 一样,可以在顶部使用 import 导入,在这个文件中的所有类都可以使用。
2)局部导入:什么时候使用,什么时候导入。在其作用范围内都可以使用
3)通配符导入:import java.util._
4)给类起名:import java.util.{ArrayList=>JL}
5)导入相同包的多个类:import java.util.{HashSet, ArrayList}
6)屏蔽类:import java.util.{ArrayList =>,}
7)导入包的绝对路径:new root.java.util.HashMap

Scala 中的三个默认导入分别是
import java.lang._
import scala._
import scala.Predef._

5.4 类和对象

定义类

[修饰符] class 类{

}不加修饰符默认为public,加上public会报错

一个scala文件可以定义多个类

class student{//该注解默认生成set get@BeanPropertyprivate var:String name = "1"//默认public 但底层都是private//假如想要属性为空 name = _ 相当于null 或0
}

5.5 封装

Scala 中的 public 属性,底层实际为 private,并通过 get 方法(obj.field())和 set 方法 (obj.field_=(value))对其进行操作。所以 Scala 并不推荐将属性设为 private,再为其设置 public 的 get 和 set 方法的做法。但由于很多 Java 框架都利用反射调用 getXXX 和 setXXX 方 法,有时候为了和这些框架兼容,也会为 Scala 的属性设置 getXXX 和 setXXX 方法(通过 @BeanProperty 注解实现)。

在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,你可以通 过类似的修饰符达到同样的效果。但是使用上有区别。

(1)Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字。

(2)private 为私有权限,只在类的内部和伴生对象中可用。

(3)protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以 访问,同包无法访问。

(4)private[包名]增加包访问权限,包名下的其他类也可以使用

5.6 构造器

和 Java 一样,Scala 构造对象也需要调用构造方法,并且可以有任意多个构造方法。

Scala 类的构造器包括:主构造器和辅助构造器

class 类名(形参列表) { // 主构造器// 类体def this(形参列表) { // 辅助构造器}def this(形参列表) { //辅助构造器可以有多个...}
}

说明:

(1)辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型 来区分。

(2)辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。

(3)构造器调用其他另外的构造器,要求被调用构造器必须提前声明。

5.7 抽象类

(1)定义抽象类:abstract class Person{} //通过 abstract 关键字标记抽象类

(2)定义抽象属性:val|var name:String //一个属性没有初始化,就是抽象属性

(3)定义抽象方法:def hello():String //只声明而没有实现的方法,就是抽象方法

继承&重写

(1)如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明 为抽象类

(2)重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override。

(3)子类中调用父类的方法使用 super 关键字

(4)子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;

子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var。

因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写

5.8 单例对象(伴生对象)

1)基本语法 object Person{ val country:String=“China” }

2)说明

(1)单例对象采用 object 关键字声明

(2)单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。

(3)单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。

apply 方法

通过伴生对象的 apply 方法,实现不使用 new 方法创建对象。

如果想让主构造器变成私有的,可以在()之前加上 private。

当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构 建对象时,调用的其实时伴生对象的 apply 方法。

5.9 特质(Trait)

就是java中的interface with来实现

基本语法

trait 特质名 {主体
}

Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法

当trait与类属性冲突时,需要重写属性,否则报错

scala都是动态绑定的

没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 …

有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3

多个特质方法冲突

img

trait Ball {def describe(): String = {"ball"}
}
trait Color extends Ball {override def describe(): String = {"blue-" + super.describe()}
}
trait Category extends Ball {override def describe(): String = {"foot-" + super.describe()}
}
class MyBall extends Category with Color {override def describe(): String = {"my ball is a " + super.describe()}
}
object TestTrait {def main(args: Array[String]): Unit = {println(new MyBall().describe())}
}
//输出结果
//my ball isa blue-foot-ball

img

5.9 类型检查和转换

(1)obj.isInstanceOf[T]:判断 obj 是不是 T 类型。

(2)obj.asInstanceOf[T]:将 obj 强转成 T 类型。

(3)classOf 获取对象的类名。

class Person{
}
object Person {def main(args: Array[String]): Unit = {val person = new Person//(1)判断对象是否为某个类型的实例val bool: Boolean = person.isInstanceOf[Person]if ( bool ) {//(2)将对象转换为某个类型的实例val p1: Person = person.asInstanceOf[Person]println(p1)}//(3)获取类的信息val pClass: Class[Person] = classOf[Person]println(pClass)}
}

5.10 枚举类和应用类

枚举类:需要继承 Enumeration

应用类:需要继承 App

// 枚举类
object Color extends Enumeration {val RED = Value(1, "red")val YELLOW = Value(2, "yellow")val BLUE = Value(3, "blue")
}
// 应用类
object Test20 extends App {println("xxxxxxxxxxx");
}

使用 type 关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名

type myString = String

第六章 集合

6.1 可变与不可变

Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable 特质。

对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两 个包

不可变集合:scala.collection.immutable

可变集合: scala.collection.mutable

Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而 不会对原对象进行修改。类似于 java 中的 String 对象

可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似 于 java 中 StringBuilder 对象

img

Array与String特殊,使用了隐式转换

Set、Map 是 Java 中也有的集合,Seq 是 Java 没有的,我们发现 List 归属到 Seq 了,但和List有不同

for 循环有一个 1 to 3,就是 IndexedSeq 下的 Range ,String 也是属于 IndexedSeq

经典的数据结构比如 Queue 和 Stack 被归属到 LinearSeq(线性序列)

Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map 可以支持排序

IndexedSeq 和 LinearSeq 的区别:

IndexedSeq 是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集

LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找

6.2 遍历

定义

定义:val arr1 = new Array[Int](10)println(arr01.length) // 4//(2)数组赋值//(2.1)修改某个元素的值arr01(3) = 10//(2.2)采用方法的形式给数组赋值arr01.update(0,1)//(3)遍历数组//(3.1)查看数组println(arr01.mkString(","))//(3.2)普通遍历for (i <- arr01) {println(i)}//(3.3)简化遍历def printx(elem:Int): Unit = {println(elem)}arr01.foreach(printx)// arr01.foreach((x)=>{println(x)})// arr01.foreach(println(_))arr01.foreach(println)//(4)增加元素(由于创建的是不可变数组,增加元素,其实是产生新的数
组)println(arr01)val ints: Array[Int] = arr01 :+ 5println(ints)}

第二种方式定义数组

val arr1 = Array(1, 2)

(1)在定义数组时,直接赋初始值

(2)使用 apply 方法创建数组对象

6.3 数组

val arr01 = ArrayBuffer[Any](3, 2, 5)
arr01.+=(4)
//(3.2)向数组最后追加数据
arr01.append(5,6)
//向指定的位置(0)插入数据
arr01.insert(0,7,8)
arr01.preappend(5,6)
//删除指定下标元素
arr.remove(0)
//从下标开始删除多个
arr.remove(1,3)
arr1.toBuffer //不可变数组转可变数组
arr2.toArray //可变数组转不可变数组
//从数组中移除 1 元素
arr -= 1 
//指定分隔符遍历
arr.mkString(", ")
//返回 length长度的range
a.indices

ArrayBuffer 是有序的集合,增加元素使用的是 append 方法(),支持可变参数

多维数组

val arr = Array.ofDim[Double](3,4)
//说明:二维数组中有三个一维数组,每个一维数组中有四个元素

6.4 列表

有顺序不能用构造器创建,底层是继承了一个抽象类

只能用apply

值不可改变,可添加

//apply方法创建
var list = List(0,1)
var list1 = Nil.::(1)
var list2 = 1 :: 2 :: 3 :: Nil
//两个类实现了List Nil空列表类 ::类 :: 方法会将元素添加到末尾并返回新的列表
//列表追加列表 :: 会返回嵌套列表 不是想要的追加元素
// ::: 此方法会合成一个完整的list 或者 ++ 
// ++ 会返回新的 ++=会覆盖第一个

可变列表

ListBuffer

可new 可apply

new ListBuffer[Int]()
//不能提前定义长度
ListBuffer(1,2)
3 +=: 4 list += 25 += 25

6.4 集合

可变set与不可变set名字都一样,只是包名不同

set是特质,使用伴生对象的apply方法,无序

方法与list一致

val list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
val list2: List[Int] = List(4, 5, 6, 7, 8, 9, 10)
//(1)获取集合的头
println(list1.head)
//(2)获取集合的尾(不是头的就是尾)
println(list1.tail)
//(3)集合最后一个数据
println(list1.last)
//(4)集合初始数据(不包含最后一个)
println(list1.init)
//(5)反转
println(list1.reverse)
//(6)取前(后)n 个元素
println(list1.take(3))
println(list1.takeRight(3))
//(7)去掉前(后)n 个元素
println(list1.drop(3))
println(list1.dropRight(3))
//(8)并集
println(list1.union(list2))
//(9)交集
println(list1.intersect(list2))
//(10)差集
println(list1.diff(list2))
//(11)拉链 注:如果两个集合的元素个数不相等,那么会将同等数量的数据进行拉链,多余的数据省略不用 嵌套的时Tuple2类型
println(list1.zip(list2))
//(12)滑窗
list1.sliding(2, 5).foreach(println)

6.5 Map

Map("a" -> 1)
var a :Map [String , String]  = Map()
map.get("a")
//不会返回value 会返回 Some(1) 想要返回value .get().get
//当没有key值时get会报异常 使用 getOrElse("c",0) 
//如果为null 赋值0
//也可以map("a") 报异常map.put("a","b")
//删除a 键值对
map -= "a"
println(map)
map += "sczc" -> "s"
map.update("scac","nu")
map += (("1","1"))
println(map)
//合并map
map ++= mutable.Map ("2"-> "2")
println(map)

6.6 元组

//元组 最大只有22个元素 创建方式跟py一样 () 下标从一开始不可变
//并不是Any类型的列表 每个元组长度都有一个单独类 Tuple1-22
var tuple = ("1",1,2.1,true)
println(tuple)
//(1,1,2.1,true)
//访问数据 tuple._number or tuple.produceElement(num)
println(tuple._1)
//迭代器遍历
for (elem <- tuple.productIterator)
println(elem)
//嵌套元组
var tuple2 = (1,2,(3,3))
println(tuple2._3._1)

集合常用函数

//(1)求和
println(list.sum)
//(2)求乘积
println(list.product)
//(3)最大值
println(list.max)
//(4)最小值
println(list.min)
//(5)排序
// (5.1)按照元素大小排序
println(list.sortBy(x => x))
// (5.2)按照元素的绝对值大小排序
println(list.sortBy(x => x.abs))
// (5.3)按元素大小升序排序
println(list.sortWith((x, y) => x < y))
// (5.4)按元素大小降序排序
println(list.sortWith((x, y) => x > y))

(1)sorted 对一个集合进行自然排序,通过传递隐式的 Ordering

(2)sortBy 对一个属性或多个属性进行排序,通过它的类型。

(3)sortWith 基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑。lamda表达式

集合计算高级函数

val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)val nestedList: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))val wordList: List[String] = List("hello world","hello atguigu", "hello scala")//(1)过滤println(list.filter(x => x % 2 == 0))//(2)转化/映射println(list.map(x => x + 1))//(3)扁平化println(nestedList.flatten)//(4)扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten
操作println(wordList.flatMap(x => x.split(" ")))//(5)分组println(list.groupBy(x => x % 2))}

Reduce 方法

通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最 终获取结果。

val list = List(1,2,3,4)// 将数据两两结合,实现运算规则val i: Int = list.reduce( (x,y) => x-y )println("i = " + i)// 从源码的角度,reduce 底层调用的其实就是 reduceLeft//val i1 = list.reduceLeft((x,y) => x-y)

Fold 折叠:化简的一种特殊情况。

val list = List(1,2,3,4)// fold 方法使用了函数柯里化,存在两个参数列表// 第一个参数列表为 : 零值(初始值)// 第二个参数列表为: 简化规则// fold 底层其实为 foldLeftval i = list.foldLeft(1)((x,y)=>x-y)val i1 = list.foldRight(10)((x,y)=>x-y

多线程

(1 to 100).par.map()  //会多个x

第七章 模式匹配

Scala 中的模式匹配类似于 Java 中的 switch 语法

var result = operator match {case '+' => a + bcase '-' => a - bcase '*' => a * bcase '/' => a / bcase _ => "illegal"
}

每个 case 中,不需要使用 break 语句,自动中断 case。

匹配类型

def describe(x: Any) = x match {case i: Int => "Int"case s: String => "String hello"case m: List[_] => "List"case c: Array[Int] => "Array[Int]"case someThing => "something else " + someThing}

匹配数组

scala 模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素 为 0 的数组。

val result = arr match {case Array(0) => "0" //匹配 Array(0) 这个数组case Array(x, y) => x + "," + y //匹配有两个元素的数
组,然后将将元素值赋给对应的 x,ycase Array(0, _*) => "以 0 开头的数组" //匹配以 0 开头和
数组case _ => "something else"}

匹配列表

def main(args: Array[String]): Unit = {val list: List[Int] = List(1, 2, 5, 6, 7)list match {case first :: second :: rest => println(first + "-" + 
second + "-" + rest)case _ => println("something else")}}

变量声明时匹配

var first :: second :: three = List(121,2 ,3.5,6)
println(s"$first  $second")//for循环简化
for((var1,var2) <- List((1,2),(3,5)))println(var1+"   "+var2)
//可以不考虑位置的值 var2换成_ 只遍历第一个值
for((var1,_) <- List((1,2),(3,5)))println(var1)
//指定位置特殊值 只遍历1开头的元组
for((1,_) <- List((1,2),(3,5)))println(var1)

匹配对象及样例类

object User{def apply(name: String, age: Int): User = new User(name, age)def unapply(user: User): Option[(String, Int)] = {if (user == null)NoneelseSome(user.name, user.age)}
}
object TestMatchUnapply {def main(args: Array[String]): Unit = {val user: User = User("zhangsan", 11)val result = user match {case User("zhangsan", 11) => "yes"case _ => "no"}println(result)}
}

当将 User(“zhangsan”, 11)写在 case 后时[case User(“zhangsan”, 11) => “yes”],会默 认调用 unapply 方法(对象提取器),user 作为 unapply 方法的参数,unapply 方法 将 user 对象的 name 和 age 属性提取出来,与 User(“zhangsan”, 11)中的属性值进行 匹配

case 中对象的 unapply 方法(提取器)返回 Some,且所有属性均一致,才算匹配成功, 属性不一致,或返回 None,则匹配失败。

样例类

case class Person (name: String, age: Int)

○1 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中 自动提供了一些常用的方法,如 apply、unapply、toString、equals、hashCode 和 copy。

○2 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例 类可以直接使用模式匹配,而无需自己实现 unapply 方法。

○3 构造器中的每一个参数都成为 val,除非它被显式地声明为 var(不建议这样做)

偏函数中的模式匹配(了解)

img功能是返回输入的 List 集合的第二个元素

第八章 隐式转换

异常处理

def main(args: Array[String]): Unit = {try {var n= 10 / 0}catch {case ex: ArithmeticException=>{// 发生算术异常println("发生算术异常")}case ex: Exception=>{// 对异常处理println("发生了异常 1")println("发生了异常 2")}}finally {println("finally")}
}

用 throw 关键字,抛出一个异常对象。所有异常都是 Throwable 的子类型。throw 表 达式是有类型的,就是 Nothing

当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用 于将类型进行转换,实现二次编译

隐式函数

class MyRichInt(val self: Int) {def myMax(i: Int): Int = {if (self < i) i else self}def myMin(i: Int): Int = {if (self < i) self else i}
}
object TestImplicitFunction {// 使用 implicit 关键字声明的函数称之为隐式函数implicit def convert(arg: Int): MyRichInt = {new MyRichInt(arg)}
def main(args: Array[String]): Unit = {// 当想调用对象功能时,如果编译错误,那么编译器会尝试在当前作用域范
围内查找能调用对应功能的转换规则,这个调用过程是由编译器完成的,所以称之为隐
式转换。也称之为自动转换println(2.myMax(6))}
}

隐式参数

普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时, 就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。

(1)同一个作用域中,相同类型的隐式值只能有一个

(2)编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。

(3)隐式参数优先于默认参数

object TestImplicitParameter {implicit val str: String = "hello world!"def hello(implicit arg: String="good bey world!"): Unit = {println(arg)}def main(args: Array[String]): Unit = {hello}
}

隐式类

隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶 级的。

object TestImplicitClass {implicit class MyRichInt(arg: Int) {def myMax(i: Int): Int = {if (arg < i) i else arg}def myMin(i: Int) = {if (arg < i) arg else i}}def main(args: Array[String]): Unit = {println(1.myMax(3))}
}
implicit var a = 1def myTest():Unit = {println("---"+ implicitly[Int])}

泛型

class MyList[+T]{ //协变 }

class MyList[-T]{ //逆变 }

class MyList[T] //不变

说明 协变:Son 是 Father 的子类,则 MyList[Son] 也作为 MyList[Father]的“子类”。

逆变:Son 是 Father 的子类,则 MyList[Son]作为 MyList[Father]的“父类”。

不变:Son 是 Father 的子类,则 MyList[Father]与 MyList[Son]“无父子关系”。

泛型上下限

Class PersonList[T <: Person]{ //泛型上限 }

Class PersonList[T >: Person]{ //泛型下限 }
Int): MyRichInt = {
new MyRichInt(arg)
}
def main(args: Array[String]): Unit = {
// 当想调用对象功能时,如果编译错误,那么编译器会尝试在当前作用域范
围内查找能调用对应功能的转换规则,这个调用过程是由编译器完成的,所以称之为隐
式转换。也称之为自动转换
println(2.myMax(6))
}
}


##  隐式参数普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时, 就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。(1)同一个作用域中,相同类型的隐式值只能有一个 (2)编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。 (3)隐式参数优先于默认参数```scala
object TestImplicitParameter {implicit val str: String = "hello world!"def hello(implicit arg: String="good bey world!"): Unit = {println(arg)}def main(args: Array[String]): Unit = {hello}
}

隐式类

隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶 级的。

object TestImplicitClass {implicit class MyRichInt(arg: Int) {def myMax(i: Int): Int = {if (arg < i) i else arg}def myMin(i: Int) = {if (arg < i) arg else i}}def main(args: Array[String]): Unit = {println(1.myMax(3))}
}
implicit var a = 1def myTest():Unit = {println("---"+ implicitly[Int])}

泛型

class MyList[+T]{ //协变 }

class MyList[-T]{ //逆变 }

class MyList[T] //不变

说明 协变:Son 是 Father 的子类,则 MyList[Son] 也作为 MyList[Father]的“子类”。

逆变:Son 是 Father 的子类,则 MyList[Son]作为 MyList[Father]的“父类”。

不变:Son 是 Father 的子类,则 MyList[Father]与 MyList[Son]“无父子关系”。

泛型上下限

Class PersonList[T <: Person]{ //泛型上限 }

Class PersonList[T >: Person]{ //泛型下限 }


http://chatgpt.dhexx.cn/article/JMOZpFH3.shtml

相关文章

Scala入门教程

教程目录 0x00 教程内容0x01 Scala 理论1. Scala 基本概念2. Scala 交互式命令行 0x03 Scala 基本语法1. 基础语法2. 标识符3. 注释4. 数据类型5. 常量和变量6. 基本函数7. 局部应用8. 柯里化函数9. 可变长度参数10. 类11. 构造函数12. 继承13. 重载方法14. 抽象类15. 特质16. …

Scala基础教程

简介 Scala是一种结合了面向对象和函数式编程的、静态类型的高级编程语言。 Scala代码被编译成.class文件&#xff0c;运行在Java虚拟机(JVM)上&#xff0c;可以调用Java类库。 官方网站&#xff1a;https://www.scala-lang.org/ 官方文档&#xff1a;https://docs.scala-lan…

scala php,Scala 教程

Scala 教程 Scala 是一门多范式(multi-paradigm)的编程语言&#xff0c;设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在Java虚拟机上&#xff0c;并兼容现有的Java程序。 Scala 源代码被编译成Java字节码&#xff0c;所以它可以运行于JVM之上&#xff0c;…

Scala详细教程

Scala详细教程 目录 Scala详细教程 1.Scala 介绍 1.1 什么是 Scala Scala 1.2 为什么要学 Scala 2.开发环境准备 2.1 ScalaSDK 安装 2.1.1Window 下安装 ScalaSDK 2.1.2Linux 下安装 ScalaSDK 2.2 IDEA 安装 2.3 IDEAScala 插件的离线安装 2.4 IDEA 创建 HelloScala…

Scala教程

1. 基础语法 Scala语言是基于Java虚拟机运行的&#xff0c;所以基本的语法和Java是没有区别的。但是为了简化Java的开发以及融合其他的编程语言的优点和特性&#xff0c;Scala在基本的语法上做了大量的修改和优化&#xff0c;让程序员开发起来更简单&#xff0c;方便&#xff…

Scala教程-详细全部

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 本文链接&#xff1a;https://blog.csdn.net/qq_39346903/article/details/113562823 文章目录 第1章 Scala入门1.1 概述1.1.1 为什么学习Scala1.…

单工,半双工和全双工有何区别和联系?

单工、半双工和全双工是电信计算机网络中的三种通信信道。这些通信信道可以提供信息传达的途径。通信信道可以是物理传输介质或通过多路复用介质的逻辑连接。物理传输介质是指能够传播能量波的材料物质&#xff0c;例如数据通信中的导线。并且逻辑连接通常指电路交换连接或分组…

单工、半双工及全双工之间的区别

1、单工数据传输只支持数据在一个方向上传输&#xff1b;在同一时间只有一方能接受或发送信息&#xff0c;不能实现双向通信&#xff0c;举例&#xff1a;电视&#xff0c;广播。 2、半双工数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实…

全双工、半双工、单工有什么区别!

什么是全双工&#xff1f; 全双工&#xff1a;&#xff08;Full Duplex&#xff09;是通讯传输的一个术语。通信允许数据在两个方向上同时传输&#xff0c;它在能力上相当于两个单工通信方式的结合。全双工指可以同时&#xff08;瞬时&#xff09;进行信号的双向传输&#xff0…

三种通信方式——单工、半双工和双工通信

数据通常是在两个站&#xff08;点对点&#xff09;之间进行传输&#xff0c;按照数据流的方向可分为三种传输模式&#xff1a;单 工、半双工、全双工。 一、单工通信&#xff08;simplex&#xff09; 单工通信只支持信号在一个方向上传输&#xff08;正向或反向&#xff09…

图文并茂~ 详解交换机中的半双工与全双工网络知识

很多学习网络知识的朋友在配置交换机时&#xff0c;时常会看到半双工与全双工的功能&#xff0c;今天带大家一起来了解下什么是半双工与全双工。 早期的网络设备HUB&#xff08;集线器&#xff09;就是半双工&#xff0c;目前基本没有人用了&#xff0c;而现在用的SWITCH&…

[网络管理]全双工与半双工的区别

同事说新办公室的网络一直不稳定&#xff0c;经常掉线延迟。检查进口线路和更换转接网线。都无法解决问题。 估计是不是进口网线中一根或者2根短路&#xff0c;那就修改下网卡属性吧。把自适应改成全双工10M模式&#xff0c;测试OK。 全双工传输 英文写法是:Full&#xff0d;Du…

单工通信、半双工通信和全双工通信

数据通信中&#xff0c;数据在线路上的传送方式可以分为 单工通信、 半双工通信和 全双工通信三种。 ewlw半双工通信&#xff1a;半双工通信是指数据可以沿两个方向传送&#xff0c;但同一时刻一个 半双工总线结构 信道只允许单方向传送&#xff0c;因此又被称为双向交替通信。…

比较全面的HTTP和TCP网络传输的单工、全双工和半双工

文章目录 单工、全双工、半双工1. 单工2. 半双工3. 全双工 HTTP协议的工作模式TCP协议的工作模式 本文参考&#xff1a; 图解网络传输单工、半双工、全双工 - 知乎 (zhihu.com) 问&#xff1a;HTTP是单工的还是双工的还是半双工的 - 简书 (jianshu.com) 关于TCP全双工模式的解释…

简析全双工与半双工的区别

全双工传输英文写法是:Full&#xff0d;Duplex Transmissions 是指交换机在发送数据的同时也能够接收数据&#xff0c;两者同步进行&#xff0c;这好像我们平时打电话一样&#xff0c;说话的同时也能够听到对方的声音。目前的交换机都支持全双工。 全双工的好处在于迟延小&…

全双工与半双工的区别

全双工传输英文写法是:Full&#xff0d;Duplex Transmissions 是指交换机在发送数据的同时也能够接收数据&#xff0c;两者同步进行&#xff0c;这好像我们平时打电话一样&#xff0c;说话的同时也能够听到对方的声音。目前的交换机都支持全双工。 全双工的好处在于迟延小&…

全双工、半双工和单工

一&#xff0c;单工、半双工和全双工的区别&#xff1a; 在串行通信中&#xff0c;数据通常是在两个终端&#xff08;如电脑和外设&#xff09;之间进行传送&#xff0c;根据数据流的传输方向可分为3种基本传送方式&#xff1a;单工、半双工和全双工。这3种传输方式的示意图和区…

单工,半双工和和全双工通讯的概念

单工&#xff1a;数据传输只支持数据在一个方向上传输&#xff1b; 半双工&#xff1a;允许数据在两个方向上传输&#xff0c;但某一时刻只允许数据在一个方向上传输&#xff0c;实际上是一种切换方向的单工通信&#xff0c;不需要独立的接收端和发送端&#xff0c;两者可合并…

单工、半双工和全双工的区别

--------------------------------------------- -- 时间&#xff1a;2018-11-06 -- 创建人&#xff1a;Ruo_Xiao -- 邮箱&#xff1a;xclsoftware163.com --------------------------------------------- 一、单工 1、数据只在一个方向上传输&#xff0c;不能实现双方通信。…

单工、双工、半双工、全双工通信常识

根据通信双方的分工和信号传输方向可将通信分为三种方式&#xff1a;单工、半双工与全双工。 单工通信&#xff0c;指通信双方设备中发送器与接收器分工明确&#xff0c;只能在由发送器向接收器的单一固定方向上传送数据&#xff0c;并且不能实现双向通信&#xff0c;例如&…