一、语系
1.动态类型语言
概念:意思就是类型的检查是在运行时做的
表现:使用变量前不需要声明变量
举例:JavaScript、Ruby、Python 这些都属于动态类型语言
2.静态类型语言
概念:意思就是类型判断是在运行前做的(如编译阶段)
表现:使用变量前需要声明变量
举例:C、C++、Java、Scala 这些都属于静态类型语言
Scala 是以java虚拟机(JVM)为目标运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言。
二、概述
1.scala是纯粹面向对象的,每个值都是对象,每个操作都是方法调用。
2.Scala是成熟的函数式语言:
①函数是头等值,也就是说函数也是值,并且和其他类型(如整数、字符串等)处于同一地位,函数可以被当作参数传递,也可以被当作返回值返回,还可以在函数中定义函数等等;
②程序的操作应该把输入值映射为输出值而不是就地修改,也就是说函数调用不应产生副作用。
虽然函数式编程语言鼓励使用“无副作用”的方法,但是scala并不强制你必须这么做。
scala允许你使用指令式的编程风格,但是随着你对scala的深入了解,你可能会更倾向于一种更为函数式的编程风格。向函数式编程转变,你就应该尽量去使用val、不可变对象、无副作用方法,而不是var、可变对象、有副作用方法。要明白的是,从指令式编程向函数式编程的转变会很困难,因此你要做好充分的准备,并不断的努力。
三、基础知识
1.在scala中,语句之后的“;”是可选的,这根据你的喜好。
(当有多个语句在同一行时,必须加上分号,但不建议把多个语句放在一行。)
2.建议使用2个空格作为代码缩进。 不过我咋喜欢一个tab呢 ⊙﹏⊙!
3.在scala中,符号“_”相当于java中的通配符“*”。
4.scala类似于c++、java,索引也l是从0开始,但元组是个例外,它从1开始。
5.scala有7种数值类型:Byte、Char、Short、Int、Long、Float和Double,以及2种非数值类型:Boolean和Unit(只有一个值“()”,相当于java和c++中的void,即空值)。
5.1这些类型都是抽象的final类(不能使用new新建,也不能被继承),在scala包中定义,是对java基本数据类型的包装,因此与 java基本数据类型有相同的长度。
5.2 scala还提供了RichInt、RichChar等等,它们分别提供Int、Char等所不具备的便捷方法。
5.3 scala沿用了java.lang包中的String。在scala中,常量也称作字面量,字符串字面量由双引号包含的字符组成。
5.4原始字符串,它以三个双引号作为开始和结束,字符串内部可以包含无论何种任意字符。
6.scala有两种变量:val和var。val如同java中的final变量,var如同java中的非final变量。
6.1 由于scala是完全面向对象的,因此val和var只是声明了对象的引用是不可变的还是可变的,并不能说明引用指向的对象的可 变性;
6.2 声明变量的同时需要初始化之,否则该变量就是抽象的;
6.3 如果不指定变量的类型,编译器会从初始化它的表达式中推断出其类型。当然你也可以在必要的时候指定其类型,但注意,在scala中变量或函数的类型总是写在变量或函数的名称的后边。例如:val answer = “yes”;val answer, message: String = “yes”;
7.scala标识符有四种形式:字母数字标识符、操作符标识符、混合标识符、字面量标识符。
字母数字标识符:跟其他语言类似,由字母、数字和下划线组成,但需注意“$”字符被保留作为scala编译器产生的标识符之用,你不要随意使用它啊。
操作符标识符:由一个或多个操作符字符组成。scala编译器将在内部“粉碎”操作符标识符以转换成合法的内嵌“$”的java标识符。若你想从java代码中访问这个标识符,就应该使用这种内部表示方式。
混合标识符:由字母数字以及后面跟着的下划线和一个操作符标识符组成。如unary_+定义了一个前缀操作符“+”。
注意scala并不提供++、--操作符。但可写为,如 a + b 相当于 a.+(b)。
字面量标识符:是用反引号`…`包含的任意字符串,scala将把被包含的字符串作为标识符,即使被包含字符串是scala的关键字。例如:你可以使用Thread.`yield`()来访问java中的方法,即使yield是scala的关键字。
8.在scala中,{}块包含一系列表达式,其结果也是一个表达式,块中最后一个表达式的值就是其值。
在scala中,赋值语句本身的值是Unit类型的。因此如下语句的值为“()”:{r = r * n; n -= 1}。因此,scala中不能多重赋值。
如下语句中的x值为“()”:x = y = 1
9.scala和其他编程语言有一个根本性差异:
在scala中,几乎所有构造出来的语法结构都有值。这个特性使得程序结构更加精简。scala内建的控制结构很少,仅有if、while、for、try、match和函数调用等而已。如此之少的理由是,scala从语法层面上支持函数字面量。
9.1.1 if表达式:
scala的if/else语法结构与java等一样,但是在scala中if/else表达式有值,这个值就是跟在if/esle后边的表达式的值。如下:
val s = if(x > 0) 1 else -1
9.1.2 同时注意:scala的每个表达式都有一个类型,比如上述if/esle表达式的类型是Int。
如果是混合类型表达式,则表达式的类型是两个分支类型的公共超类型。
String和Int的超类型就是Any。如果一个if语句没有else部分,则当if条件不满足时,表达式结果为Unit。如:if(x > 0) 1
就相当于:if(x > 0) 1 else ()
备注:Unit 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。
9.2 while循环:scala拥有与java和c++中一样的while和do-while循环,while、do-while结果类型是Unit。
9.3 for表达式:scala中没有类似于for(; ; )的for循环,你可以使用如下形式的for循环语句:for(i <- 表达式)
该for表达式语法对于数组和所有集合类均有效。具体介绍如下:
9.3.1 枚举:for(i <- 1 to 10),其中“i <- 表达式”语法称之为发生器,该语句是让变量i(注意此处循环变量i是val的(但无需你 指定),该变量的类型是集合的元素类型)遍历表达式中的所有值。1 to 10产生的Range包含上边界,如果不想包含上 边界,可以使用until。
9.3.2 过滤:也叫守卫,在for表达式的发生器中使用过滤器可以通过添加if子句实现,如:for(i <- 1 to 10 if i!=5),如果要添 加多个过滤器,即多个if子句的话,要用分号隔开,如:for(i <- 1 to 10 if i!=5; if i!=6)。
9.3.3 嵌套枚举:如果使用多个“<-”子句,你就得到了嵌套的“循环”,如:for(i <- 1 to 5; j <- 1 to i)。
9.3.4 流间变量绑定:你可以在for发生器以及过滤器等中使用变量保存计算结果,以便在循环体中使用,从而避免多次计算 以得到该结果。流间变量绑定和普通变量定义相似,它被当作val,但是无需声明val关键字。
9.3.5 制造新集合:for(…) yield 变量/循环体,最终将产生一个集合对象,集合对象的类型与它第一个发生器的类型是兼容的。
9.3.6 实际上:for表达式具有等价于组合应用map、flatMap、filter和foreach这几种高阶函数的表达能力。
实际上,所有的能够yield(产生)结果的for表达式都会被编译器转译为高阶方法map、flatMap及filter的组合调用;
所有的不带yield的for循环都会被转译为仅对高阶函数filter和foreach的调用。正是由于这几个高阶函数支持了for表达式, 所以如果一个数据类型要支持for表达式,它就要定义这几个高阶函数。有些时候,你可以使用for表达式代替map、 flatMap、filter和foreach的显式组合应用,或许这样会更清晰明了呢。
10. scala中没有break和continue语句。如果需要类似的功能时,我们可以:
1) 使用Boolean类型的控制变量
2) 使用嵌套函数,你可以从函数当中return
11. match表达式与模式匹配:
11.1scala中没有switch,但有更强大的match。它们的主要区别在于:
① 任何类型的常量/变量,都可以作为比较用的样本;
② 在每个case语句最后,不需要break,break是隐含的;
③ 更重要的是match表达式也有值;
④ 如果没有匹配的模式,则MatchError异常会被抛出。
11.2 match表达式的形式为:选择器 match { 备选项 }。
一个模式匹配包含了一系列备选项,每个都开始于关键字case。
每个备选项都包含了一个模式以及一到多个表达式,它们将在模式匹配过程中被计算。箭头符号“=>”隔开了模式和表达 式。按照代码先后顺序,一旦一个模式被匹配,则执行“=>”后边的表达式((这些)表达式的值就作为match表达式的值), 后续case语句不再执行。示例如下:
a match {
case 1 => "match 1"
case _ => "match _"
}
11.3 match模式的种类如下:
① 通配模式:可以匹配任意对象,一般作为默认情况,放在备选项最后,如:case _ =>
② 变量模式:类似于通配符,可以匹配任意对象,不同的是匹配的对象会被绑定在变量上,之后就可以使用这个变量操 作对象。所谓变量就是在模式中临时生成的变量,不是外部变量,外部变量在模式匹配时被当作常量使用,见常量模 式。注意:同一个模式变量只能在模式中出现一次。
③ 常量模式:仅匹配自身,任何字面量都可以作为常量,外部变量在模式匹配时也被当作常量使用,
如:case "false" => "false"
case true => "truth"
case Nil => "empty list"
对于一个符号名,是变量还是常量呢?scala使用了一个简单的文字规则对此加以区分:用小写字母开始的简单名被当作 是模式变量,所有其他的引用被认为是常量。如果常量是小写命名的外部变量,那么它就得特殊处理一下了:如果它是对 象的字段,则可以加上“this.”或“obj.”前缀;或者更通用的是使用字面量标识符解决问题,也即用反引号“`”包围之。
④ 抽取器模式:抽取器机制基于可以从对象中抽取值的unapply或unapplySeq方法,其中,unapply用于抽取固定数量的东 东,unapplySeq用于抽取可变数量的东东,它们都被称为抽取方法,抽取器正是通过隐式调用抽取方法抽取出 对应东东的。抽取器中也可以包含可选的apply方法,它也被称作注入方法,注入方法使你的对象可以当作构造 器 来用,而抽取方法使你的对象可以当作模式来用,对象本身被称作抽取器,与是否具有apply方法无关。样本 类会自动生成伴生对象并添加一定的句法以作为抽取器,实际上,你也可以自己定义一个任意其他名字的单例对 象作为抽取器使用,以这样的方式定义的抽取器对象与样本类类型是无关联的。你可以对数组、列表、元组进行模 式匹配,这正是基于抽取器模式的。
⑤ 类型模式:你可以把类型模式当作类型测试和类型转换的简易替代,示例如下:
case s: String => s.length
⑥ 变量绑定:除了独立的变量模式之外,你还可以把任何其他模式绑定到变量。只要简单地写上变量名、一个@符号,以 及这个模式。
模式守卫:模式守卫接在模式之后,开始于if,相当于一个判断语句。守卫可以是任意的引用模式中变量的布尔表达式。 如果存在模式守卫,只有在守卫返回true的时候匹配才算成功。
Option类型:scala为可选值定义了一个名为Option的标准类型,一个Option实例的值要么是Some类型的实例,要么是 None对象。分离可选值最通常的办法是通过模式匹配,如下:
case Some(s) => s
case None => “?”
模式无处不在:在scala中,模式可以出现在很多地方,而不单单在match表达式里。比如:
① 模式使用在变量定义中,如下:
val myTuple = (123, “abc”)
val (number, string) = myTuple
② 模式匹配花括号中的样本序列(即备选项)可以用在能够出现函数字面量的任何地方,实质上,样本序列就是更普遍的函 数字面量,函数字面量只有一个入口点和参数列表,样本序列可以有多个入口点,每个都有自己的参数列表,每个样本 都是函数的一个入口点,参数被模式所特化。如下:
val withDefault: Option[Int] => String = {
case Some(x) => "is int"
case None => "?"
}
③ for表达式里也可以使用模式。示例如下:
for((number, string) <- myTuple) println(number + string)
模式匹配中的中缀标注:带有两个参数的方法可以作为中缀操作符使用,使用中缀操作符时实际上是其中一个操作 数在调用操作符对应的方法,而另一个操作数作为方法的参数。但对于模式来说规则有些不同:如果被当作模式, 那么类似于p op q这样的中缀标注等价于op(p,q),也就是说中缀标注符op被用做抽取器模式。