Scala详细总结精辟版++.docx

上传人:b****0 文档编号:8966844 上传时间:2023-05-16 格式:DOCX 页数:43 大小:537.50KB
下载 相关 举报
Scala详细总结精辟版++.docx_第1页
第1页 / 共43页
Scala详细总结精辟版++.docx_第2页
第2页 / 共43页
Scala详细总结精辟版++.docx_第3页
第3页 / 共43页
Scala详细总结精辟版++.docx_第4页
第4页 / 共43页
Scala详细总结精辟版++.docx_第5页
第5页 / 共43页
Scala详细总结精辟版++.docx_第6页
第6页 / 共43页
Scala详细总结精辟版++.docx_第7页
第7页 / 共43页
Scala详细总结精辟版++.docx_第8页
第8页 / 共43页
Scala详细总结精辟版++.docx_第9页
第9页 / 共43页
Scala详细总结精辟版++.docx_第10页
第10页 / 共43页
Scala详细总结精辟版++.docx_第11页
第11页 / 共43页
Scala详细总结精辟版++.docx_第12页
第12页 / 共43页
Scala详细总结精辟版++.docx_第13页
第13页 / 共43页
Scala详细总结精辟版++.docx_第14页
第14页 / 共43页
Scala详细总结精辟版++.docx_第15页
第15页 / 共43页
Scala详细总结精辟版++.docx_第16页
第16页 / 共43页
Scala详细总结精辟版++.docx_第17页
第17页 / 共43页
Scala详细总结精辟版++.docx_第18页
第18页 / 共43页
Scala详细总结精辟版++.docx_第19页
第19页 / 共43页
Scala详细总结精辟版++.docx_第20页
第20页 / 共43页
亲,该文档总共43页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Scala详细总结精辟版++.docx

《Scala详细总结精辟版++.docx》由会员分享,可在线阅读,更多相关《Scala详细总结精辟版++.docx(43页珍藏版)》请在冰点文库上搜索。

Scala详细总结精辟版++.docx

Scala详细总结精辟版++

Scala总结

--2015-1-1912:

33:

54

本文档针对scala2.10.x,由于scala目前发展迅速,因此可能会和其他版本的不同。

===概述

scala是一门以java虚拟机(JVM)为目标运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言。

scala是纯粹的面向对象的语言。

java虽然是面向对象的语言,但是它不是纯粹的,因为java的基本数据类型不是类,并且在java中还有静态成员变量和静态方法。

相反,scala是纯粹面向对象的,每个值都是对象,每个操作都是方法调用。

scala也是一个成熟的函数式语言。

函数式编程有两个指导思想:

①函数是头等值,也就是说函数也是值,并且和其他类型(如整数、字符串等)处于同一地位,函数可以被当作参数传递,也可以被当作返回值返回,还可以在函数中定义函数等等;②程序的操作应该把输入值映射为输出值而不是就地修改,也就是说函数调用不应产生副作用,虽然函数式编程语言鼓励使用“无副作用”的方法,但是scala并不强制你必须这么做。

scala允许你使用指令式的编程风格,但是随着你对scala的深入了解,你可能会更倾向于一种更为函数式的编程风格。

向函数式编程转变,你就应该尽量去使用val、不可变对象、无副作用方法,而不是var、可变对象、有副作用方法。

要明白的是,从指令式编程向函数式编程的转变会很困难,因此你要做好充分的准备,并不断的努力。

scala运行于JVM之上,并且它可以访问任何的java类库并且与java框架进行互操作,scala也大量重用了java类型和类库。

第一个scala程序:

objectScalaTest{

defmain(args:

Array[String]){

println("helloscala.")

}

}

===scala解释器

安装好scala并配置好PATH环境变量之后,就可以在终端中输入“scala”命令打开scala解释器。

在其中,你可以像使用shell一样,使用TAB补全、Ctrl+r搜索、上下方向键切换历史命令等等。

退出scala解释器,可以使用命令:

“:

q”或者“:

quit”。

由于解释器是输入一句执行一句,因此也常称为REPL。

REPL一次只能看到一行代码,因此如果你要在其中粘贴代码段的话,可能会出现问题,这时你可以使用粘贴模式,键入如下语句:

:

paste

然后把代码粘贴进去,再按下Ctrl+d,这样REPL就会把代码段当作一个整体来分析。

===scala作为脚本运行

scala代码也可以作为脚本运行,只要你设置好代码文件的shell前导词(preamble),并将代码文件设置为可执行。

如下:

#!

/usr/bin/envscala

println("这是scala脚本")

设置代码文件为可执行,即可执行之啦。

scala脚本的命令行参数保存在名为args的数组中,你可以使用args获取命令行输入的程序参数。

===scala编译运行

scala编译器scalac会将scala代码编译为jvm可以运行的字节码,然后就可以在jvm上执行了。

假设有一个Hello.scala文件,我们就可以使用scalacHello.scala编译,然后使用scalaHello运行。

当然也可以使用java工具来运行,但需要在classpath里指定scala-library.jar。

对于classpath,在Unix家族的系统上,类路径的各个项目由冒号“:

”分隔,在MSWindows系统上,它们由分号“;”分隔。

例如,在linux上你可以输入这样的命令来运行(注意classpath最后加一个“.”):

java-classpath/usr/local/scala-2.10.4/lib/scala-library.jar:

.Hello

===scalaIDE开发环境

你可以使用eclipse或者intellijidea作为scala的IDE开发环境,但都需要安装scala插件才行。

下面分别介绍这两种方式:

eclipse开发环境配置:

scalaideforeclipse(下载地址:

http:

//scala-ide.org)中集成了scala插件,你可以直接使用它进行开发,不过它包含的可能不是我们想要的scala版本,因此,还是在该网站上下载对应的scala插件,插在eclipse上,这样更好啊。

我们先安装eclipsejuno,然后下载eclipsejuno以及scala2.10.4对应的scalasdk插件升级包:

update-site.zip。

将插件解压缩,将features和plugins目录下的所有东东都复制到eclipse中的对应目录中,重启eclipse即可。

然后就可以新建scalaproject了。

intellijidea开发环境配置:

我们先安装好intellijidea,然后安装scala插件,自动安装插件有时会非常慢,尤其是在china。

我们还是手动配置插件吧。

请注意插件的版本,必须与当前idea版本兼容。

手动配置插件方法如下:

(1)进入setting>plugins>browserepositorits搜索你要下载的插件名称,右侧可以找到下载地址。

(2)解压插件压缩包,把插件的全部文件都复制到IntelliJIDEA安装程序的plugins文件夹中,注意插件最好以一个单独的文件夹放在plugins目录下。

(3)一般重启intellijidea就会自动加载插件,进入setting>plugins看看有木有。

如果不自动加载的话,进入setting>plugins>installpluginfromdisk,找到刚才复制的插件位置,再然后就好了。

接下来就可以新建scalaproject,新建时我选择的是“Scala”(不是sbt,因为我这选择sbt之后,等半天sbt都不会配置好,郁闷啊)。

相关姿势:

什么是SBT?

SBT=(notso)SimpleBuildTool,是scala的构建工具,与java的maven地位相同。

其设计宗旨是让简单的项目可以简单的配置,而复杂的项目可以复杂的配置。

===scala特点

在scala中,语句之后的“;”是可选的,这根据你的喜好。

当有多个语句在同一行时,必须加上分号,但不建议把多个语句放在一行。

在scala中,建议使用2个空格作为代码缩进,不过我咋喜欢一个tab呢⊙﹏⊙!

在scala中,符号“_”相当于java中的通配符“*”。

scala类似于c++、java,索引也是从0开始,但元组是个例外,它从1开始。

===数据类型

scala有7种数值类型:

Byte、Char、Short、Int、Long、Float和Double,以及2种非数值类型:

Boolean和Unit(只有一个值“()”,相当于java和c++中的void,即空值)。

这些类型都是抽象的final类(不能使用new新建,也不能被继承),在scala包中定义,是对java基本数据类型的包装,因此与java基本数据类型有相同的长度。

同时,scala还提供了RichInt、RichChar等等,它们分别提供Int、Char等所不具备的便捷方法。

另外,scala沿用了java.lang包中的String。

在scala中,常量也称作字面量,字符串字面量由双引号包含的字符组成,同时scala提供了另一种定义字符串常量的语法——原始字符串,它以三个双引号作为开始和结束,字符串内部可以包含无论何种任意字符。

在scala中,我们使用方法,而不是强制类型转换,来做数值类型之间的转换,如99.44.toInt、97.toChar。

另外也可以参见显式类型转换和隐式转换。

===变量

scala有两种变量:

val和var。

val如同java中的final变量,var如同java中的非final变量。

由于scala是完全面向对象的,因此val和var只是声明了对象的引用是不可变的还是可变的,并不能说明引用指向的对象的可变性。

声明变量的同时需要初始化之,否则该变量就是抽象的。

如果不指定变量的类型,编译器会从初始化它的表达式中推断出其类型。

当然你也可以在必要的时候指定其类型,但注意,在scala中变量或函数的类型总是写在变量或函数的名称的后边。

示例如下:

valanswer=“yes”

valanswer,message:

String=“yes”

===标识符

scala标识符有四种形式:

字母数字标识符、操作符标识符、混合标识符、字面量标识符。

字母数字标识符:

跟其他语言类似,由字母、数字和下划线组成,但需注意“$”字符被保留作为scala编译器产生的标识符之用,你不要随意使用它啊。

操作符标识符:

由一个或多个操作符字符组成。

scala编译器将在内部“粉碎”操作符标识符以转换成合法的内嵌“$”的java标识符。

若你想从java代码中访问这个标识符,就应该使用这种内部表示方式。

混合标识符:

由字母数字以及后面跟着的下划线和一个操作符标识符组成。

如unary_+定义了一个前缀操作符“+”。

字面量标识符:

是用反引号`…`包含的任意字符串,scala将把被包含的字符串作为标识符,即使被包含字符串是scala的关键字。

例如:

你可以使用Thread.`yield`()来访问java中的方法,即使yield是scala的关键字。

===操作符

scala的操作符和你在java和C++中的预期效果是一样的,但注意scala并不提供++、--操作符。

不过,scala中的操作符实际上都是方法,任何方法都可以当作操作符使用,如a+b相当于a.+(b)。

需要注意的是:

对于不可变对象(注:

对象的不可变并不是说它的引用变量是val的),并不真正支持类似于“+=”这样以“=”结尾的操作符(即方法),不过scala还是提供了一些语法糖,用以解释以“=”结尾的操作符用于不可变对象的情况。

假设a是不可变对象的引用,那么在scala中a+=b将被解释为a=a+b,这时就相当于新建一个不可变对象重新赋值给引用a,前提是引用变量a要声明为var的,因为val变量定义之后是不可变的。

更多信息参见函数(方法)部分。

===块表达式与赋值

在scala中,{}块包含一系列表达式,其结果也是一个表达式,块中最后一个表达式的值就是其值。

在scala中,赋值语句本身的值是Unit类型的。

因此如下语句的值为“()”:

{r=r*n;n-=1}

正是由于上述原因,scala中不能多重赋值,而java和c++却可以多重赋值。

因此,在scala中,如下语句中的x值为“()”:

x=y=1

===控制结构

scala和其他编程语言有一个根本性差异:

在scala中,几乎所有构造出来的语法结构都有值。

这个特性使得程序结构更加精简。

scala内建的控制结构很少,仅有if、while、for、try、match和函数调用等而已。

如此之少的理由是,scala从语法层面上支持函数字面量。

if表达式:

scala的if/else语法结构与java等一样,但是在scala中if/else表达式有值,这个值就是跟在if/esle后边的表达式的值。

如下:

vals=if(x>0)1else-1

同时注意:

scala的每个表达式都有一个类型,比如上述if/esle表达式的类型是Int。

如果是混合类型表达式,则表达式的类型是两个分支类型的公共超类型。

String和Int的超类型就是Any。

如果一个if语句没有else部分,则当if条件不满足时,表达式结果为Unit。

如:

if(x>0)1

就相当于:

if(x>0)1else()

while循环:

scala拥有与java和c++中一样的while和do-while循环,while、do-while结果类型是Unit。

for表达式:

scala中没有类似于for(;;)的for循环,你可以使用如下形式的for循环语句:

for(i<-表达式)

该for表达式语法对于数组和所有集合类均有效。

具体介绍如下:

枚举:

for(i<-1to10),其中“i<-表达式”语法称之为发生器,该语句是让变量i(注意此处循环变量i是val的(但无需你指定),该变量的类型是集合的元素类型)遍历表达式中的所有值。

1to10产生的Range包含上边界,如果不想包含上边界,可以使用until。

过滤:

也叫守卫,在for表达式的发生器中使用过滤器可以通过添加if子句实现,如:

for(i<-1to10ifi!

=5),如果要添加多个过滤器,即多个if子句的话,要用分号隔开,如:

for(i<-1to10ifi!

=5;ifi!

=6)。

嵌套枚举:

如果使用多个“<-”子句,你就得到了嵌套的“循环”,如:

for(i<-1to5;j<-1toi)。

流间变量绑定:

你可以在for发生器以及过滤器等中使用变量保存计算结果,以便在循环体中使用,从而避免多次计算以得到该结果。

流间变量绑定和普通变量定义相似,它被当作val,但是无需声明val关键字。

制造新集合:

for(…)yield变量/循环体,最终将产生一个集合对象,集合对象的类型与它第一个发生器的类型是兼容的。

实际上:

for表达式具有等价于组合应用map、flatMap、filter和foreach这几种高阶函数的表达能力。

实际上,所有的能够yield(产生)结果的for表达式都会被编译器转译为高阶方法map、flatMap及filter的组合调用;所有的不带yield的for循环都会被转译为仅对高阶函数filter和foreach的调用。

正是由于这几个高阶函数支持了for表达式,所以如果一个数据类型要支持for表达式,它就要定义这几个高阶函数。

有些时候,你可以使用for表达式代替map、flatMap、filter和foreach的显式组合应用,或许这样会更清晰明了呢。

scala中没有break和continue语句。

如果需要类似的功能时,我们可以:

1)使用Boolean类型的控制变量

2)使用嵌套函数,你可以从函数当中return

3)...

match表达式与模式匹配:

scala中没有switch,但有更强大的match。

它们的主要区别在于:

1任何类型的常量/变量,都可以作为比较用的样本;

2在每个case语句最后,不需要break,break是隐含的;

3更重要的是match表达式也有值;

4如果没有匹配的模式,则MatchError异常会被抛出。

match表达式的形式为:

选择器match{备选项}。

一个模式匹配包含了一系列备选项,每个都开始于关键字case。

每个备选项都包含了一个模式以及一到多个表达式,它们将在模式匹配过程中被计算。

箭头符号“=>”隔开了模式和表达式。

按照代码先后顺序,一旦一个模式被匹配,则执行“=>”后边的表达式((这些)表达式的值就作为match表达式的值),后续case语句不再执行。

示例如下:

amatch{

case1=>"match1"

case_=>"match_"

}

match模式的种类如下:

1通配模式:

可以匹配任意对象,一般作为默认情况,放在备选项最后,如:

case_=>

2变量模式:

类似于通配符,可以匹配任意对象,不同的是匹配的对象会被绑定在变量上,之后就可以使用这个变量操作对象。

所谓变量就是在模式中临时生成的变量,不是外部变量,外部变量在模式匹配时被当作常量使用,见常量模式。

注意:

同一个模式变量只能在模式中出现一次。

3常量模式:

仅匹配自身,任何字面量都可以作为常量,外部变量在模式匹配时也被当作常量使用,如:

case"false"=>"false"

casetrue=>"truth"

caseNil=>"emptylist"

对于一个符号名,是变量还是常量呢?

scala使用了一个简单的文字规则对此加以区分:

用小写字母开始的简单名被当作是模式变量,所有其他的引用被认为是常量。

如果常量是小写命名的外部变量,那么它就得特殊处理一下了:

如果它是对象的字段,则可以加上“this.”或“obj.”前缀;或者更通用的是使用字面量标识符解决问题,也即用反引号“`”包围之。

4抽取器模式:

抽取器机制基于可以从对象中抽取值的unapply或unapplySeq方法,其中,unapply用于抽取固定数量的东东,unapplySeq用于抽取可变数量的东东,它们都被称为抽取方法,抽取器正是通过隐式调用抽取方法抽取出对应东东的。

抽取器中也可以包含可选的apply方法,它也被称作注入方法,注入方法使你的对象可以当作构造器来用,而抽取方法使你的对象可以当作模式来用,对象本身被称作抽取器,与是否具有apply方法无关。

样本类会自动生成伴生对象并添加一定的句法以作为抽取器,实际上,你也可以自己定义一个任意其他名字的单例对象作为抽取器使用,以这样的方式定义的抽取器对象与样本类类型是无关联的。

你可以对数组、列表、元组进行模式匹配,这正是基于抽取器模式的。

5类型模式:

你可以把类型模式当作类型测试和类型转换的简易替代,示例如下:

cases:

String=>s.length

6变量绑定:

除了独立的变量模式之外,你还可以把任何其他模式绑定到变量。

只要简单地写上变量名、一个@符号,以及这个模式。

模式守卫:

模式守卫接在模式之后,开始于if,相当于一个判断语句。

守卫可以是任意的引用模式中变量的布尔表达式。

如果存在模式守卫,只有在守卫返回true的时候匹配才算成功。

Option类型:

scala为可选值定义了一个名为Option的标准类型,一个Option实例的值要么是Some类型的实例,要么是None对象。

分离可选值最通常的办法是通过模式匹配,如下:

caseSome(s)=>s

caseNone=>“?

模式无处不在:

在scala中,模式可以出现在很多地方,而不单单在match表达式里。

比如:

1模式使用在变量定义中,如下:

valmyTuple=(123,“abc”)

val(number,string)=myTuple

2模式匹配花括号中的样本序列(即备选项)可以用在能够出现函数字面量的任何地方,实质上,样本序列就是更普遍的函数字面量,函数字面量只有一个入口点和参数列表,样本序列可以有多个入口点,每个都有自己的参数列表,每个样本都是函数的一个入口点,参数被模式所特化。

如下:

valwithDefault:

Option[Int]=>String={

caseSome(x)=>"isint"

caseNone=>"?

"

}

3for表达式里也可以使用模式。

示例如下:

for((number,string)<-myTuple)println(number+string)

模式匹配中的中缀标注:

带有两个参数的方法可以作为中缀操作符使用,使用中缀操作符时实际上是其中一个操作数在调用操作符对应的方法,而另一个操作数作为方法的参数。

但对于模式来说规则有些不同:

如果被当作模式,那么类似于popq这样的中缀标注等价于op(p,q),也就是说中缀标注符op被用做抽取器模式。

===函数

函数定义:

定义函数时,除了递归函数之外,你可以省略返回值类型声明,scala会根据=号后边的表达式的类型推断返回值类型,同时=号后边表达式的值就是函数的返回值,你无需使用return语句(scala推荐你使用表达式值代替return返回值,当然根据你的需要,也可以显式使用return返回值)。

示例如下:

defabs(x:

Double)=if(x>=0)xelse-x

deffac(n:

Int)={

varr=1

for(i<-1ton)r=r*i

r

}

对于递归函数必须指定返回值类型,如下:

deffac(n:

Int):

Int=if(n<=0)1elsen*fac(n-1)

但你要知道的是:

声明函数返回类型,总是有好处的,它可以使你的函数接口清晰。

因此建议不要省略函数返回类型声明。

函数体定义时有“=”时,如果函数仅计算单个结果表达式,则可以省略花括号。

如果表达式很短,甚至可以把它放在def的同一行里。

去掉了函数体定义时的“=”的函数一般称之为“过程”,过程函数的结果类型一定是Unit。

因此,有时定义函数时忘记加等号,结果常常是出乎你的意料的。

没有返回值的函数的默认返回值是Unit。

函数调用:

scala中,方法调用的空括号可以省略。

惯例是如果方法带有副作用就加上括号,如果没有副作用就去掉括号。

如果在函数定义时,省略了空括号,那么在调用时,就不能加空括号。

另外,函数作为操作符使用时的调用形式参见相应部分。

函数参数:

一般情况下,scala编译器是无法推断函数的参数类型的,因此你需要在参数列表中声明参数的类型。

对于函数字面量来说,根据其使用环境的不同,scala有时可以推断出其参数类型。

scala里函数参数的一个重要特征是它们都是val(这是无需声明的,在参数列表里你不能显式地声明参数变量为val),不是var,所以你不能在函数里面给参数变量重新赋值,这将遭到编译器的强烈反对。

重复参数:

在scala中,你可以指明函数的最后一个参数是重复的,从而允许客户向函数传入可变长度参数列表。

要想标注一个重复参数,可在参数的类型之后放一个星号“*”。

例如:

defecho(args:

String*)=for(arg<-args)println(arg)

这样的话,echo就可以被零至多个String参数调用。

在函数内部,重复参数的类型是声明参数类型的数组。

因此,echo函数里被声明为类型“String*”的args的类型实际上是Array[String]。

然而,如果你有一个合适类型的数组,并尝试把它当作重复参数传入,会出现编译错误。

要实现这个做法,你需要在数组名后添加一个冒号和一个_*符号,以告诉编译器把数组中的每个元素当作参数,而不是将整个数组当作单一的参数传递给echo函数,如下:

echo(arr:

_*)

默认参数与命名参数:

函数的默认参数与java以及c++中相似,都是从左向右结合。

另外,你也可以在调用时指定参数名。

示例如下:

deffun(str:

String,left:

String=“[”,right:

String=“]”)=left+str+right

fun(“hello”)

fun(“hello”,“<<<”)

fun(“hello”,left=“<<<”)

函数与操作符:

从技术层面上来说,scala没有操作符重载,因为它根本没有传统意义上的操作符。

诸如“+”、“-”、“*”、“/”这样的操作符,其实调用的是方法。

方法被当作操作符使用时,根据使用方式的不同,可以分为:

中缀标注(操作符)、前缀标注、后缀标注。

中缀标注:

中缀操作符左右分别有一个操作数。

方法若只有

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2