map写法 scala语言_Scala语言

Scala中函数是一等公民,可以不依赖对象直接创建函数,Scala将函数式编程和面向对象编程融合在一起。​Scala中将对象属性和对象方法与类属性和类方法进行了分离,Scala中的对象相关属性和方法通过 class关键字定义在对象域中,而类相关的属性和方法通过 object关键字定义在 伴生对象中(Scala中没有 static关键字,伴生对象编译后会生成 原始对象的class文件(类名.class)和 伴生对象的class文件(类名$.class)​笔记语法中的”“ 代表用户必填项,”[xxx]“ 代表选填项

一、基本语法

声明变量:var|val [: 变量类型] = [变量值]

Scala中分号可不写val代表不可变量,编译后加上 final修饰

8c3056ea7770d36a934c3726d0511c18.png

特殊类型说明

Unit

等同于 void

Null

引用类型,但只有一个null实例

Nothing

在Scala继承链最底层,是任何类的子类,利用 多态在我们确定一个函数不会正常返回的时候,可以将返回值(异常)返回给其他变量(因为是子类)

Scala中值类型转换

向下转型直接赋值

向上转型在值上调用 toXxx(如:toDouble、toInt)强制转换函数

Scala中不支持三目运算符(即:?:),全部使用 if-else方式实现Scala中也没有 switch语句,而是使用 match-case匹配模式实现

Scala中for循环控制

// 打印1到3,闭区间

for(i

print(i);

}

// 打印1到3,前闭后开

for(i

print(i)

}

// 直接遍历集合

val list = List("h",1,2.2);

for(item

println(item)

}

// 循环守卫(也称条件判断式),判断为true进入循环,false则跳过循环

for(i

println(i);

}

// 循环返回值,对循环中处理的结果返回到一个新的Vector集合中

var res = for(i

// 控制步长,打印1到10 步长为2

for(i

println(i)

}

二、函数式编程基础

在Scala中函数也被当做一种数据类型,可以作为方法的参数传递,Scala中将没有返回值的函数/方法也称为 过程

在类中定义方法:

def ([数名称:参数类型]....)[:返回值类型[=]]{[语句...][return 返回值]}

直接定义函数:

val func ([数名称:参数类型]....)[:返回值类型] =>{[语句...][return 返回值]}

将对象的方法转换为独立的函数:

val func = obj.func _;

形参为空可以省略()

def ([数名称:参数类型]....)={...}表示返回值类型不确定(最后一条语句不能带 return关键字),运行时类型推导完成,语句可以返回 多种类型

def ([数名称:参数类型]....):{...}表示返回值类型在编译期就确定,语句中只能返回 一种类型

def ([数名称:参数类型]....){...}表示没有返回值(即等价于返回值Unit),即使语句中有return也不生效,这种函数也叫 过程

如果没有return语句,默认语句的最后一行结果作为返回值

如果写了语句最后写了return关键字,则返回值类型就不能省略,函数返回不能自行推导

形参列表和返回值的数据类型可以是值类型和引用类型

在Scala中声明函数/方法形参列表时,可以指定默认值

可变参数写法

def (参数名:参数类型*){[语句...]}

惰性函数

在将函数返回值赋值给其他变量时候,将这个变量声明为lazy,则该函数不会立即执行,只会在取值的时候才会计算,这种函数叫 惰性函数

lazy可以修饰val变量,但不能修饰var变量。指定了该变量后也会在用到的时候才会赋值

三、类与对象

3.1 基础

Scala没有public关键字,定义类的时候 属性默认为private修饰并且默认编译后会提供 属性名()的方法用来获取该方法,和 属性名_$eq()方法用来设置该属性,如果定义属性时添加上private则编译后不会再添加这两个方法,需要开发者自己提供。定义类的时候 方法默认为public修饰,protected修饰的属性或者方法只能对子类访问,而子包不能访问​Scala还通过object关键字来定义 伴生对象,将所有类属性和类方法全部定义到 伴生对象中

[:类型] = new ();

3.2 构造器

Scala包含 主构造器和 辅助构造器,在scala中体现了函数编程和面向对象编程的思想结合,定义主构造器放在类名之后,且 主构造器会执行直接放在类中的所有语句。伴生对象可以通过def apply():={}方式定义工厂方法,通过 伴生对象创建对象时不用new直接使用类名(实参列表)形式

1.想让主构造器变私有,则在()前加上 private2.主构造器无参数可以省略类名后面的()3.构造器参数未使用任何访问符,则形参是局部变量4.构造器参数使用var定义会则编译后会将变量作为private属性并提供 xxx()方法和xxx_$eq()方法5.构造器参数使用val定义则编译后变量用private final修饰并提供 xxx()方法6.创建对象时必须为属性指定初始值,也可以用 -赋值初始值7.只有 主构造器可以调用 父类构造器,但是不能通过super调用,可以通过extends 父类(参数)的方式给符类构造器传递参数8*.在类上加上@BeanProperty注解,会自动生成setter和getter方法

3.3 包

3.3.1 包定义

Scala中的包可以嵌套使用,子包可以 直接访问父包内容,而父包要通过import来访问子包内容,并且引入包的时候,只能访问该包下面的类,而不能递归访问子包下面的类(即import不是精确引入,不会递归引入)​包中可以包含类\对象\特质(trait),但是不能包含变量和方法,这是虚拟机局限,因此Scala通过包对象来解决.(每一个包只能有一个包对象)包中对象可以直接调用包对象定义的属性和方法

定义语法:package object {[语句...]}

定义方法和属性时候private和protected修饰的成员后面可以通过 [包名]来扩大可见性

3.3.2 包引入

Scala中的包可以在任何需要的地方引入,从而降低import包的作用范围。

// Scala中可以在引包的时候将类定义别名

import java.utils.{HashMap=>JavaHashMap}

// Scala在引入包的时候可以制定忽略某些类

import java.utils.{HashMap=_,_}

3.4 继承

Scala只支持单继承使用extends关键字,子类继承了父类所有的属性和方法,只是私有属性和方法不能在子类访问​Scala中不存在Java继承时属性存在的动态绑定问题,因为Scala继承属性的时会把属性的属性名()和属性名_$eq()一起继承过去,相当于 重写方法​Scala中引用类型强制类型转换通过asInstanceOf[父类]来转换,通过isInstanceOf来判断类型​Scala使用trait关键字声明特质(等同java中的接口),当一个类继了特质,就可以用该特质来引用该类的实例对象

声明时使用特质:class extends with with with

创建对象时使用特质(动态混入): 对象名 = new 类名 with with 创建对象时按照定义顺序从左到右加载(初始化特质),而调用覆盖的特质方法时,会从右向左调用,程序运行过程中不管有无继承关系特质2中 super指的是特质1 ,如果想让特质2指向自己的 真实父类,可以通过 泛型即:super[特质直接父类].xxx(...)的方式调用

既有抽象方法又有具体方法的特质也叫 富接口混入了特质的类,特质中的属性直接加入该类作为类的属性(对象属性或者类属性具体看特质如何定义),并且特质中抽象的字段(未赋值)在具体的类中必须初始化

特质可以继承具体的类(相当于Java中的接口可以继承具体的类),然后可以扩展类的功能,混入该特质的类只能继承该特质的超类

特质继承了具体的类,如果想限制实现该特质的类 必须是特质超类的子类才能调用该方法,则可以在方法前加上this.=>的限定

3.5 内部类

// 创建内部类

new Outter().Inner()

// 创建静态内部类,在伴生对象中定义

new Outter.Inner()

通过 别名=>class 内部类的形式将 外部类.this替换为前面的 别名,这种方式在定义 别名的时候要将外部类属性放在别名定义之后,否则编译错误。非静态内部类默认与 外部类对象关联,如果方法需要调用自身 非静态内部类对象,即屏蔽外对象对内部类对象影响可以通过类型投影,具体做法就是在 非静态内部类调用自身的方法的形参前面加上 外部类#前缀,表示忽略内部类对象之间关系。

3.6 隐式

1. 隐式转换函数式通过implicit声明 有且只有一个参数的函数,这种函数在它作用域范围内 自动调用,因为是 自动调用它的名称并不重要。只是与 函数签名有关(函数的 参数列表以及 返回值)

implicit def ( ):{[语句...]}

2. 通过implicit声明的变量叫 隐式值,如果函数要使用 隐式值需要在 形参前面也加上 implicit,这样调用该 拥有隐式值形参的函数在调用时如果没有传入参数,则会在作用范围内寻找通过implicit声明的 隐式值作为实参。隐式值的优先级要大于定义形参时指定的 形参默认值

3. 隐式类通过`implicit`声明在类、伴生对象、包对象中(即:隐式类不能作为顶级类),**主构造器** 只能包含一个参数作为在该范围内被识别并转换的类型(形参不需要`implicit`修饰),在 **隐式类** 作用范围内通过 **隐式类主构造器参数类型的对象** 调用 **隐式类中的方法**(在该类型对象中没定义该方法),则在编译过后会通过 **将该类型对象作为参数传入隐式类,然后通过隐式类调用隐式类中方法** 的方式调用 **隐式类中的方法**,来在隐式类作用范围内增强指定对象

decd65ddb21018f34a89e20bb30caf54.png

四、集合基本使用

在Scala中集合分为两种:变长集合、定长集合,并且有时候会用到Java中的集合,则会通过 隐式转换在两者之间互相转换。

4.1 Array

// 直接创建定长数组(泛型是可选的,但必须指定集合长度),不能直接print全部元素

val array = new Array[Int](3);

// 通过集合伴生对象的apply方法创建定长数组,可以直接print全部元素

val array = List(1,2,3);

// 定义多维数组(只能是定长)

val arrayDim = Array.ofDim[Int](3,4) //3行4列,元素Int类型

// 定长集合是定义在scala包中的不需要引入,而变长集合需要单独引用

import scala.collection.mutable.ArrayBuffer

// 定长集合转换为变长集合

val arrayBuffer = array.toBuffer;

// 创建变长数组

val arrayBuffer = new ArrayBuffer[Int](3);

// 向变长数组添加元素

arrayBuffer.append(1);

// 变长集合转换为定长集合

val array = arrayBuffer.toArray;

// Scala数组转换为Java数组(因为Java数组是变长,所以只能中Scala中的ArrayBuffer转换)

// 导入隐式转换函数

import scala.collection.JavaConversions.bufferAsJavaList

val scalaArr = new ArrBuffer[Int](3);

// 该方法会需要Java的ArrayList,调用时会被引入的隐式转换函数识别转换为ArrayList

val javaArr = new ProcessBuilder(scala);

// Java数组转换为Scala数组

import scala.collection.JavaConversions.asScalaBuffer

val scalaArr:mutable.Buffer[Int] = javaArr;

4.2 Tuple

元组是一个容器可以存放相同或者不同的元素作为一个整体,Scala中元组最大可以存储22个元素,Tuple1~Tuple22不同的元素个数是不同的元组类型

// 元组定义

val tuple = (1,2,"hello",4);

// 元组访问

print(tuple._2);// 访问元组第二个元素

4.3 List

默认情况下Scala中的List是不可变(如果用可变则需要ListBuffer),并且是一个对象可以直接存储数据。

//--------------------不可变List

// 创建list

val list = List(1,2,3);

// 创建空集合

val list = Nil;

// 访问list元素

print(list(1));//访问第二个元素

// 在list之后追加数据

val list2 = list:+4;//list并没有改变,而是返回一个添加元素后的新集合

// 在list之前添加数据

val list = 4+:list

// 将每一个元素加到集合中

val list = 1::2::3::List(1,2,3)::Nil;

// 将集合分解,并把集合中的每个元素添加到指定末尾集合中

val list = 1::2::3::List(1,2,3):::Nil;

//----------------------可变ListBuffer

import scala.collection.mutable.ListBuffer

// 创建可变list

val listBuffer = ListBuffer(1,2,3);

// 从可变list删除元素

listBuffer-=1;

// 向可变list添加元素

listBuffer+=1;

// 合并另外一个集合(可以是不变list)

listBuffer++list;

4.4 Queue

在Scala中有scala.collection.mutable.Queue和scala.collection.immutable.Queue两种队列,一般开发中用到的是可变队列

// 创建可变队列

import scala.collection.mutable.Queue

val queue = Queue(1,2,3);

// 向队尾增加元素

queue+=4;

// 向对位添加集合中的所有元素

queue++=List(1,2,3);

// 从队列头部取出元素

queue.dequeue();

// 向队列尾部添加元素

queue.enqueue(4,5,6);

// 返回队首元素(对队列无影响)

queue.head;

// 返回队尾元素(对队列无影响)

queue.last;

// 返回除第一个意外的所有元素

queue.tail;

4.5 Map

在Scala中有scala.collection.mutable.Map和scala.collection.immutable.Map两种Map,默认是不可变Map,其中不可变Map有序,可变map无序。在Scala底层Map元素是Tuple2类型

// 创建Map

val map = Map("a"->10,"b"->20);

// 以二元组形式创建Map

val map = Map(("a",10),("b",20));

// 使用map取值,如果key不存在则抛出异常

map.map("a");

// 检查元素是否存在

map.contains("a");

// get取值,如果存在返回some,不存在返回none

map.get("a").get

// getOrElse取值,如果不存在返回默认值(第二个参数指定的值)

map.getOrEles("a","默认值");

// 添加元素

map+=("c"->30,"d"->40);

// 删除元素

map-=("c"->30,"d"->40);

// 取出的元素是Tuple2类型,因此遍历可以通过元组的方式访问

for(ele

4.6 Set

在Scala中有scala.collection.mutable.Set和scala.collection.immutable.Set两种Map,默认是不可变Map

// 创建可变set

import scala.collection.mutable.Set

val set = Set(1,2,3);

// 向set中添加元素

set+=4;

// 在set中删除元素

set-=4;

###

五、集合高级使用

5.1 映射操作

将集合中的每一个元素通过 映射函数转换为新结果集合

val list = List(1,2,3);

list.map(x=>x+1)

5.2 扁平化

val list = List(1,2,3);

list.flatMap(_.toString);

5.3 元素过滤

val list = List(1,2,3);

list.filter(_>2);

5.4 化简

val list = List(1,2,3);

// 左边第一个元素开始迭代向后执行函数

list.reduce(_+_);//等同于reduceLeft

5.5 折叠

val list = List(1,2,3);

list.fold(4)(_+_);//等价于在集合左侧添加元素后执行第二个函数参数

4/:list(_+_)

5.6 扫描

// 对集合的每个元素进行fold操作,让后将所有中间结果保存到一个集合中

val list = List(1,2,3);

val list2 = list.scan(4)(_+_);

5.7 拉链合并

val list1 = List(1,2,3);

val list2 = List(4,5,6);

list1.zip(list2);//配对形成元组集合(1,4),(2,5),(3,6)

5.8 迭代器

迭代器遍历元素只能访问一次,第二次访问需要重新获取迭代器

val list = List(1,2,3);

val iterator = list.iterator;

while(iterator.hasNext){

iterator.next()

}

// 重新获取迭代器,以临另一种方式迭代

for(ele

ele;

}

5.9 流

steam是一个存放无穷元素的集合,主要用来通过指定规则动态生成元素。末尾元素遵循lazy规则

def numsForm(n:BigInt):Stream[BigIni]=n#::numsForm(n+1)

numsFrom(4).tail

5.10 视图

使用视图对集合的所有操作并不会立即执行,而是在用到集合元素的时候才去执行

val list = List(1,2,3)

list.view.filter(_>1);

5.11 并行集合

val list = List(1,2,3);

list.par.map(_+2);

5.12 操作符扩展

class oper{

var money:Int = _;

// 对中置操作符重载

def +(n:Int):Unit={

this.money+=n;

}

// 对后置操作符重载

def ++():Unit={

this.money+=1

}

// 对前置操作符重载,方法前需要加上unary_前缀

def unary_!():Unit={

this.money=-money;

}

}

六、模式匹配

6.1 基本介绍

val oper = '+';

oper match{

case '+'=>print("加法");

// 如果都没匹配,最终会执行 case_后面的语句

case _=>

}

6.2 守卫

val num =120

num match{

//此时的_不表示默认匹配

case _if(mun>100)=>print(num)

case _=>

}

6.3 模式中的变量

val a = "aaaa"

a match{

// 将a中的值传递给mystring

case mystring => print(mystring);

case _ =>

}

val b = ‘b’

b match{

// match中可以有返回值,默认case的最后一条语句为返回值

case ‘b’ => "hello";

case _ =>

}

6.4 匹配集合

Array(0) // 匹配只有一个元素且为0的数组

Array(x,y) // 匹配数组有两个元素并将两个元素赋值x,y

Array(0,_*) // 匹配数组以0开始

0::Nil // 匹配只有一个元素且为0的List

x::y::Nil // 匹配有两个元素并将两个元素赋值为x,y

0::tail // 匹配第一个元素为0的List

(0,_) // 匹配第一个元素为0的tuple2

(y,0) // 匹配第二个元素为0的tuple2,并把第一个元素赋值为x

6.5 对象匹配

// 伴生对向的unapply方法返回Some集合为匹配成功,返回None集合为返回失败

Object Square{

def unapply(d:Double):Option[Double]={

Some(math.qurt(d))

}

}

val num = 10.1

num match{

// 调用Square的unapply方法隐式传入num,返回结果Some的值赋给n

case Square(n) => print(n);

case _ =>

}

6.6 样例模式

// 声明样例类后面必须带一个参数,该参数默认用val修饰作为不可变属性

case class A(v:Int){}

6.7 密封类

通过sealed关键字声明的类的所有子类必须在相同源文件中定义

七、函数式高级编程

7.1 偏函数

// 匿名内部类形式定义偏函数,表示接受的参数是Any,返回值类型是Int,collect支持偏函数,map不支持偏函数

val paritalFum = new ParitalFunction[Any,Int]{

// 如果返回true 会调用 apply方法创建对象,如果为false则过滤掉元素

override def isDefinedAt(x:Any)={

}

// 返回Int类型对象

override def apply(v:Any)={

}

}

// 简化形式,返回类型必须统一,如果不统一返回类型是Any

val list = List(1,2,3).collcet{

case i:Int=>i+1;

case j:Double=>(j+1).toInt;

case _ =>

}

7.2 匿名函数

val fun = (x:Int)=>{

x+1

}

7.3 高阶函数

能够 接收函数作为参数的函数或者 能够返回函数的的函数叫做 高阶函数

// 接受函数作为参数

// 接受Double类型的参数返回Int类型参数

def fun(f:Double=>Int,n:Double){

f(n)

}

// 返回函数作为参数,也称为闭包

def minusxy(x:Int){

(y:Int)=>x+y;

}

// 或者直接使用匿名函数返回高阶函数,也称为闭包

val fun = (x:Int)=>{

(y:Int)=>x+y

}

// 闭包就是一个函数与相关引用环境组合成的一个整体

7.4 参数类型推断

参数类型可以推断时,可以省略参数类型

传递函数时,只有单个参数可以省略括号

如果参数的变量(无论=>左侧有多少变量),在=>右侧只出现一次,则可以省略=>以及左侧内容,右侧内容的所有变量用_表示

7.5 函数柯里化

将 接收多个参数的函数转化为接受 单个参数的的函数的过程就叫 柯里化

// 通过柯里化比较字符串大小并且转换成小写

implicit class TestEq(s:String){

def checkEq(str:String)(f:(String,String)=>Boolean):Boolean={

f(s.toLowerCase,str.toLowerCase);

}

}

// 调用

val str = "Hello";

str.checkEq(str)(_.equals(_));

7.6 抽象控制

抽象控制是一类特殊的函数,它的 参数是函数,函数没有输入值也没有返回值

def abstractCtrl(f:=>Unit){

f

}

// 直接将语句块传入到f函数中

abstractCtrl{

// 语句块

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值