走进Scala

mac2024-06-03  30

1. 了解Scala

1.1Scala来源

​ Scala名字由来:Scalable Language两个单词相结合;意大利语中 scala意为“梯子”或“楼梯”,蕴含“更佳的编程语言”。

​ Martin Odersky(马丁·奥德斯基)于2001年基于Funnel的工作开始设计Scala。Funnel是把函数式编程思想和Petri网相结合的一种编程语言。Martin Odersky先前的工作是Generic Java和javac(Sun Java编译器)。

​ Java平台的Scala于2003年底/2004年初发布。.NET平台的Scala发布于2004年6月。该语言第二个版本,v2.0,发布于2006年3月。

截至2009年9月,最新版本是版本2.7.6。Scala 2.8预计的特性包括重写的Scala类库(Scala collections library)、方法的命名参数和默认参数、包对象(package object),以及Continuation.​

​ Scala 的预期目标是将面向对象、函数式编程和强大的类型系统结合起来,同时让人要能写出优雅、简洁的代码。

​ Scala博采众长,Scala采用了Java和C#语法的大部分,而他们大部分借自于C,C++语法。表达式、语句、和代码块和Java一样,还有类、包和引用的语法。除语法之外,Scala还采用了Java的其他元素,如它的基本类型、类库和它的执行模式。函数式编程借鉴了SML,OCaml,和F#为代表的ML家族语言很接近,Scala的隐式参数灵感来自Haskell,基于actor的并发库来自EeLang的思想。

1.2 Scala语言特点

面向对象

Scala是一种面向对象的语言,Scala中的每个值都是一个对象,包括基本数据类型(即布尔值、数字等)在内,连函数也是对象。

类可以被子类化,而且Scala还提供了基于mixin的组合(mixin-based composition)。

类抽象机制的扩展有两种途径:一种途径是子类继承,另一种途径是灵活的混入机制。这两种途径能避免多重继承的种种问题。

函数式编程

Scala也是一种函数式语言,其函数也能当成值来使用。Scala提供了轻量级的语法用以定义匿名函数,支持高阶函数,允许嵌套多层函数,并支持柯里化。Scala的case class及其内置的模式匹配相当于函数式编程语言中常用的代数类型。

更进一步,程序员可以利用Scala的模式匹配,编写类似正则表达式的代码处理XML数据。

静态类型

Scala具备类型系统,通过编译时检查,保证代码的安全性和一致性。类型系统具体支持以下特性:

泛型类

协变和逆变

标注

类型参数的上下限约束

把类别和抽象类型作为对象成员

复合类型

引用自己时显式指定类型

视图

多态方法

扩展性

Scala的设计秉承一项事实,即在实践中,某个领域特定的应用程序开发往往需要特定于该领域的语言扩展。Scala提供了许多独特的语言机制,可以以库的形式轻易无缝添加新的语言结构:

任何方法可用作前缀或后缀操作符

可以根据预期类型自动构造闭包。

并发性

Scala使用Actor作为其并发模型,Actor是类似线程的实体,通过邮箱发收消息。Actor可以复用线程,因此可以在程序中可以使用数百万个Actor,而线程只能创建数千个。在2.10之后的版本中,使用Akka作为其默认Actor实现。

1.3 函数式编程

函数式编程是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。

纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。

函数式编程的特点:

函数是一等公民

以表达式为中心

无副作用

只用纯函数来构造程序,或者说函数没有副作用。 什么是副作用? 一个带有副作用的函数不仅有一个返回值,还可能做了 修改一个变量 直接修改数据结构 设置一个对象的成员 打印到终端或者读取用户输入 读取或写入一个文件 在屏幕上绘画 抛出一个异常或以一个错误终止一个函数在程序执行过程中除了根据输入参数给出运算结果外,没有其他的影响,就称为没有副作用的。

不修改状态

引用透明

函数式编程优势:

代码简洁,开发速度快

接近自然语言,易理解

易于代码管理

适合并发编程

适用于热升级

函数式编程的一个特点就是,函数也是值,同允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

1.4 为什么要学Scala

1.优雅:这是框架设计师第一个要考虑的问题,框架的用户是应用开发程序员,API是否优雅直接影响用户体验。

2.速度快:Scala语言表达能力强,一行代码抵得上Java多行,开发速度快;Scala是静态编译的,所以和JRuby,Groovy比起来速度会快很多。

3.能融合到Hadoop生态圈:Hadoop现在是大数据事实标准,Spark并不是要取代Hadoop,而是要完善Hadoop生态。JVM语言大部分可能会想到Java,但Java做出来的API太丑,或者想实现一个优雅的API太费劲。

2.Scala基础

2.1编码规范

2.1.1文件名和编码

源文件名必须和它包含的顶层类名保持一致,包括大小写,并以.scala作为后缀名。

所有源文件编码必须是 UTF-8

2.1.2 特殊字符

空格

除了换行符之外,ASCII空格(0x20)是唯一合法的空格字符。这意味着

所有在源代码中(包括字符、字符串以及注释中)出现的其他空格字符需要转义,例如 Tab 用\t表示。

缩进必须使用 4个空格 而不是 Tab

新增 4个 空格

特殊转义字符

对于有特殊转义表示的字符 \b, \t, \n, \f, \r, \", \', \\,禁止使用其它等价转义方式。例如\012或者\u00a表示。

2.1.3 代码书写规范

列宽

每行不超过150个字符

缩进

4个空格,严禁使用Tab

括号的使用

基本原则:K&R风格。

左花括号({)前不能换行,在其后换行。

在右花括号(})前要有换行。

如果右花括号是一句语句、一个方法、构造函数或非匿名类的结尾,其后需要换行。

new MyClass() { // 左花括号前不能换行,在其后换行    @Override    def method():Unit= {        if (condition()) {            try {                do {                    something()               } while (!stop()) // do-while中间的右花括号后           } catch { // try-catch中间的右花括号后无需换行                case e:Exception =>recover()           } // try-catch结束,右花括号后需要换行       } else { // if-else中间的右花括号后无需换行            doSomethingElese()       } // if-else结束,右花括号后需要换行   }

其他:scala中的简单表达式可以省略括号

// 推荐 def square(x: Int) = x * x val y = if (x < 0) -x else x if(cond1){  // one line statement }else{  // one line statement }

空行的使用

在以下情况下增加空行:

在类的不同的成员间增加空行,包括:成员变量、构造函数、方法、内部类、静态初始化块、实例初始化块等两个成员变量声明之间可以不加空行。空行通常用于对成员变量进行逻辑分组。

方法体内,按需增加空行,以便从逻辑上对语句进行分组

禁止使用连续的空行。

2.1.4 注释风格

使用java风格的注释,不用使用scala风格

/** 单行注释 */ // 单行注释 /** * java风格的多行注释 * 推荐使用 */ /** scala风格的注释 * 不推荐使用 */

2.1.5 命名规范

基本原则:驼峰命名,命名有业务含义。

val orderName = "name"

2.2 变量

2.2.1 变量声明

基本语法:

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

使用var或者val定义一个变量。

使用var(variable)声明变量-可以被重新赋值。

// 定义变量a2,手动指定类型为Int,此时需要保证所赋值类型匹配 var i2: Int = 2 // 变量间可以互相赋值,并可以使用var重新定义 i1 = i2

使用val(value)声明常量-引用不可变

val修饰的变量,相当于Java中final修饰的变量;

// 定义常量s1,使用字符串"1"赋值,自动推断为String类型,值不可变 val s1 = "1" // 定义常量s2,手动指定类型为String,此时需要保证所赋值类型匹配 val s2: String = "2" // 使用val定义基本数据类型时,值不可变,可以使用val重新定义

变量声明一定要初始化

2.2.2 变量推断

含义:声明变量时,可以不指定变量类型,编译器会根据赋值内容自动推断当前变量的类型。

// 定义变量a1,使用1赋值,自动推断为Int类型 var i1 = 1 print(i1.isInstanceOf[Int]) //类型确定后,就不能再赋值的类型 i1 = 1.1

2.2.3 多变量定义

//Java中支持一行同时定义多个同类变量:    String a = "Hello", c = "hello";      int x = 5, y = 5;   //scala中的多个变量的初始化:     val (a, b, c) = (1, 2, "a") // 定义变量a3,a4,同时赋值为10 var i3,i4 = 10;

2.2.4 var和val的区别

val和var的区别

1,内容是否不变

2, val修饰的变量在编译后,等同于加上final

3,是否可以有lazy修饰.val修饰的变量还可以用lazy修饰

只有val修饰的变量才能被lazy修饰;使用lazy定义变量后,只有在调用该变量时才会实例化这个变量的值。而且惰性变量只能是不可变变量;

类似方法,先声明,后调用

scala> val a = 10 a: Int = 10 scala> lazy val b = 100 b: Int = <lazy> scala> b res2: Int = 100 scala> var c = 10 c: Int = 10 scala> lazy var d = 100 <console>:1: error: lazy not allowed here. Only vals can be lazy       lazy var d = 100            ^ scala> def e = 1000 e: Int scala> e res3: Int = 1000

使用var 声明一个变量。

var修饰的变量,内容和引用都可变

使用val声明一个常量或值

val修饰的变量是不可变的,注意不可变的不是内容,而是引用;

(扩展一下什么是值类型,什么是引用类型,可以使用数组举例,引用不可变,变的是内容。)

/**可变和不可变? 可变和不可变,指的是变量本身存的内容,值类型变量存的是数据本身,而引用类型变量存的是数据的引用, ​ 值类型和引用类型? 值类型与引用类型区别: 存储方式:直接存储数据本身 vs 存储的是数据的引用,数据存储在数据堆中 内存分配:分配在栈中 vs 分配在堆中 效率:效率高,不需要地址转换 vs 效率较低,需要进行地址转换 内存回收: 使用完后立即回收 vs 使用完后不立即回收,而是交给GC处理回收 */ scala> val arr = Array(1,2,3,4,5) arr: Array[Int] = Array(1, 2, 3, 4, 5) scala> arr = Array(1,2,3) <console>:8: error: reassignment to val       arr = Array(1,2,3) scala> arr(0)=10 scala> arr res1: Array[Int] = Array(10, 2, 3, 4, 5)

使用val 还是var

官方推荐val使用val的好处:1,更安全2,代码可读性更高3,资源回收更快,方法执行完,val所定义的变量即回收

Scala数据类型的位数,不受具体OS的影响,以保证Scala程序的可移植性。

2.2.5 数值类型

Scala和Java一样,有8种数值类型Byte、Char、Short、Int、Long、Float、Double和一个Boolean类型,

和Java不同的是 ,Scala没有基本类型与包装类型之分,这些类型都是类,有自己的属性和方法。

2.2.6 字符串类型

println("""welcome to           "1000phone".""") //为了解决每行的空格,引入了stripMargin方法。使用方式是把管道符号(|)放在每行前面,然后对整个字符串调用该方法。 println("""|welcome to           |"1000phone".""".stripMargin)

2.2.7 Unit和布尔类型

Unit

// Unit为空类型,相当于void,使用()进行初始化 var u = ()

2.2.8其他类型

Any

// Any可以接收任意的基本类型和引用类型 var any: Any = null any = anyR any = anyV

AnyRef

// 可以使用AnyRef接收任意的引用类型 var anyR: AnyRef = null

在 Scala 中,字符串的类型实际上是 Java String,它本身没有 String 类。在 Scala 中,String 是一个不可变的对象,所以该对象不可被修改。这就意味着你如果修改字符串就会产生一个新的字符串对象。

AnyVal

// 可以使用AnyVal接收任意的基本类型 var anyV: AnyVal = u // Unit anyV = b1 // Boolean anyV = b // Byte anyV = s // Short anyV = c // Char anyV = i // Int anyV = f // Float anyV = l // Int anyV = d // Double anyV = str // String

Null

// null值只能被推断为Null类型,null代表空值,可以被赋值给任何 AnyRef类型的常量或变量 var n = null

Nothing

Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。 当一个函数,我们确定没有正常的返回值,可以用Nothing 来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性)

Option

Scala Option(选项)类型用来表示一个值是可选的(有值或无值)。

val myMap: Map[String, String] = Map("key1" -> "value") val value1: Option[String] = myMap.get("key1") val value2: Option[String] = myMap.get("key2") println(value1) // Some("value1") println(value2) // None

2.2.9 操作符注意点

a + b 等价于 a.+(b)

Scala没有++,-- 可以用+=,-=代替

操作符都是方法的重载,是方法的调用

最新回复(0)