Scala基础(二)
单例类
一个object是一个只有一个实例的类,它在被引用的时候才创建,像一个lazy val。
作为一个顶层的值,一个object就是一个单例。
作为一个封闭类的成员或局部变量,它表现的就很像一个lazy val。
定义一个单例对象
一个object是一个值,定义一个object就像一个类,只是用object关键字
object Box
这里有一个简单的只有一个方法的object。
package logging object Logger { def info(message: String): Unit = println(s"INFO: $message") }
这个info方法可以在程序的任意地方被引入。像这样创建工具方法是单例对象的常见用例。让我们看看如何在另外的包中使用info
import logging.Logger.info class Project(name: String, daysToComplete: Int) class Test { val project1 = new Project("TPS Reports", 1) val project2 = new Project("Website redesign", 5) info("Created projects") // Prints "INFO: Created projects" }
由于这个import logging.Logger.info import语句,info方法就变得可见了。
import需要一个稳定路径(stable path)指向被引入的符号,一个object就是一个稳定路径。
注意:如果一个object不是顶层的,而是嵌入在另一个class或object中。那么这个object就是和其他任何成员一样的路径相关(path-dependent)的。这意味着给定两种饮料,class Milk和class OrangeJuice,一个类成员object NutritionInfo 依赖于封闭实例,milk或orange juice。milk.NutritionInfo和oj.NutritionInfo是完全不同的。
伴随对象(Companion object)
和类的名字一样的对象称为伴随对象(companion object)。相反的,这个类是这个对象的伴随类(companion class)。一个伴随类或伴随对象可以访问它的同伴的私有成员。为伴随类中和特定对象无关的方法和值用一个伴随对象。
import scala.math._ case class Circle(radius: Double) { import Circle._ def area: Double = { calculateArea(radius) } } object Circle { private def calculateArea(radius: Double): Double = { Pi * pow(radius, 2.0) } def main(args: Array[String]): Unit = { val circle1 = new Circle(5.0) println(circle1.area) } }
类Circle有一个对于每个实例都不一样的成员area,单例object Circle有一个对于每个实例都可用的方法calculateArea。
伴随对象也可以包含工厂方法(factory method):
package tour.singleton_objects class Email(val username: String, val domainName: String) object Email { def fromString(emailString: String): Option[Email] = { emailString.split('@') match { case Array(a, b) => Some(new Email(a, b)) case _ => None } } def main(args: Array[String]): Unit = { val scalaCenterEmail = Email.fromString("scala.center@epfl.ch") scalaCenterEmail match { case Some(email) => { println( s"""Registered an email |Username: ${email.username} |Domain name: ${email.domainName} """) } case None => { println("Error: could not parse email") } } } }
object Email包含一个工厂方法fromString,从一个字符串创建一个Email实例。考虑到解析错误,我们返回一个Option[Email]。
注意:如果一个类或对象有一个伴随,它们必须都定义在同一个文件中。为了在REPL中定义伴随,可以在同一行定义它们,或者进入:paste模式。
Java中的static成员可以作为Scala中伴随对象的普通成员的模型。
当使用Java代码中的伴随对象时,成员将会在一个伴随类中用static修饰符定义。这个称谓static forwarding。即使你没有为你自己定义一个伴随类也会发生这种情况。
正则表达式匹配
正则表达式是可以用来在数据中查找模式的字符串。任何字符串都可以通过 .r 方法转变成正则表达式。
package tour.regex import scala.util.matching.Regex object RegexExample { def main(args: Array[String]): Unit = { val numberPattern: Regex = "[0-9]"r numberPattern.findFirstMatchIn("awesomepassword") match { case Some(_) => println("Password OK") case None => println("Password must contain a number") } } }
在上面的例子中,numberPattern是一个Regex,我们用它来确保密码中包含数字。
我们也可以用小括号来搜索正则表达式的组(group)。
package tour.regex import scala.util.matching.Regex object RegexExample { def regexTest() = { val numberPattern: Regex = "[0-9]"r numberPattern.findFirstMatchIn("awesomepassword") match { case Some(_) => println("Password OK") case None => println("Password must contain a number") } } def regexGroupTest(): Unit = { val keyValuePattern: Regex = "([0-9a-zA-Z-#() ]+): ([0-9a-zA-Z-#() ]+)".r val input: String = """background-color: #A03300; |background-image: url(img/header100.png); |background-position: top center; |background-repeat: repeat-x; |background-size: 2160px 108px; |margin: 0; |height: 108px; |width: 100%;""".stripMargin for (patternMatch <- keyValuePattern.findAllMatchIn(input)) { println(s"key: ${patternMatch.group(1)} value: ${patternMatch.group(2)}") /** * key: background-color value: #A03300 * key: background-image value: url(img * key: background-position value: top center * key: background-repeat value: repeat-x * key: background-size value: 2160px 108px * key: margin value: 0 * key: height value: 108px * key: width value: 100 */ } } def main(args: Array[String]): Unit = { regexTest() regexGroupTest() } }
这里我们解析字符串中键值对,每个匹配有一组子匹配。
提取对象(Extractor Objects)
一个extractor object是一个有一个unapply方法的对象。apply方法像一个构造函数,接受参数并创建对象,但是unapply接受一个对象,然后尝试恢复参数。这个在pattern matching和部分函数(partial function)中经常用到。
package tour.class_related import scala.util.Random object CustomerID { def apply(name: String) = { println("call apply") s"$name--${Random.nextLong()}" } def unapply(customerID: String): Option[String] = { println("call unapply") val name = customerID.split("--").head if (name.nonEmpty) Some(name) else None } def main(args: Array[String]): Unit = { val customerID = CustomerID("Sukyoung") println("next call match") customerID match { case CustomerID(name) => println(name) case _ => println("Could not extract a CustomerID") } } }
上面这段程序会打印:
call apply
next call match
call unapply
Sukyoung
apply方法从一个name创建了一个CustomerID, unapply完成了相反的动作,把name找回来了。当我们调用CustomerID("Sukyoung")时,这是调用CustomerID.apply("Sukyoung")的简写语法。当我们调用case CustomerID(name) => println(name)时,我们调用了unapply方法。
unapply方法也可以被用于赋值。
val customer2ID = CustomerID("Nico") val CustomerID(name) = customer2ID println(name) // prints Nico
这等于val name = CustomerID.unapply(customer2ID).get,如果没有匹配的,会抛出scala.MatchError。
val CustomerID(name2) = "--asdfasdfasdf"
unapply的返回值应该从以下选项中选择一个:
- 如果只是一个测试,可以放回一个Boolean。例如case even()
- 如果他们返回类型的一个次值(sub-value),返回一个Option[T]
- 如果你想要放回多个次值T1,T2,...,Tn,用一个Option元组将它们组合起来Option[(T1,T2,...,Tn)]
有的时候,次值的数量不是固定的,我们想要返回一个列表(sequence)。为了这个原因,你也可以通过unapplySeq来定义模式,返回Option[Seq[T]]。这个机制在模式case List(x1,...,xn)的实例中使用。
相关推荐
#### 二、Scala基础语法 ##### 1. 声明值和变量 Scala中的值和变量可以通过`val`和`var`关键字进行声明: - `val`: 定义一个不可变的值(即常量)。 - `var`: 定义一个可变的变量。 ```scala val num = 0 var ...
首先,书中会介绍Scala的基础语法,包括变量、常量、表达式和控制流。Scala的变量声明不同于传统的静态类型语言,它支持类型推断,使得代码更简洁。同时,Scala的控制流结构,如if-else、while和for循环,也比Java等...
Scala 于 2003 年底 /2004 年初发布,第二个版本 v2.0 发布于 2006 年 3 月。 Scala 的特性 Scala 的关键特性包括: * 面向对象特性 * 支持命令式风格和函数式风格 * 自适应静态类型 * 简洁性 * 基于事件的并发...
### 关于《云Spark开发基础之Scala快餐第二版》的知识点提炼 #### 一、Scala与函数式编程 - **Scala的特点**: - **语言背景**:Scala是一种结合了面向对象编程和函数式编程特点的多范式编程语言。由于Spark的...
Scala编程第二版是一本深受读者喜爱的编程指南,豆瓣评分高达8.0,这足以证明其在编程领域的权威性和实用性。Scala是一种多范式编程语言,融合了面向对象和函数式编程的特点,使得它在处理大数据和分布式计算时,如...
**Scala基础知识** 1. **类型系统**:Scala拥有强类型系统,类型推断机制使代码更简洁。例如,变量定义时可以省略类型,编译器会自动推断。 2. **对象和类**:Scala将面向对象编程中的类和对象紧密结合。任何东西...
#### 三、Scala基础语法 **声明变量**: Scala支持多种类型的变量声明方式,如`val`用于声明不可变变量,`var`用于声明可变变量。 **常用类型**: Scala支持各种内置类型,如整型(`Int`)、浮点型(`Double`)、...
1. **Scala基础**:首先,书本会介绍Scala的基本语法,如变量定义、数据类型(包括基本类型和复杂类型如数组和集合)、控制结构(如if-else、for循环和while循环)、函数和方法等。 2. **面向对象编程**:Scala是...
通过学习《Scala.pdf中文高清第二版》,初学者将能够掌握Scala的基本用法和高级特性,为从事现代软件开发打下坚实基础。这本书的高清版意味着阅读体验更佳,有助于深入理解和掌握每一个知识点。
#### Scala基础语法 - **变量声明**: - Scala中声明变量使用`val`(用于不可变变量)或`var`(用于可变变量)。与Java相比,Scala更简洁,例如,`var age = 28`。 - **常量声明**: - 使用`val`关键字声明常量...
### 编程在Scala:第二版 #### 书籍概述 《Programming in Scala》第二版是一本全面详尽的Scala编程指南,由Scala语言的主要设计者Martin Odersky、Lex Spoon和Bill Venners共同撰写。本书是为Scala 2.8版本更新的...
第二种风格是通过嵌套来表示层级关系,一个源文件可以声明多个包,子包中的类可以直接访问父包的内容,无需显式导入。 此外,Scala还支持包对象,它是包下所有类和对象的共享变量,可以直接访问。包对象可以通过`...
描述中提到的三份文档——"快学scala第一章习题答案.doc"、"快学scala第二章习题答案.doc"、"快学scala第三章习题答案.doc"——暗示了这份学习资料是按照章节结构编排的,每个章节都有对应的习题和详尽的答案。...
"快学Scala第二版本示例代码" 提供了一种系统性的学习途径,帮助开发者深入理解Scala的核心概念和实践应用。 首先,从文件名列表来看,我们可以看到一系列按照章节组织的代码示例,比如`ch20`到`ch03`。这暗示了...
在课程内容上,Scala编程基础分为三个模块:Scala基础语法、Scala中的集合和函数以及Scala面向对象。每个模块都旨在帮助学员理解Scala编程的核心概念,并能在实际开发中运用。 第一模块,Scala基础语法,是学习...
#### 二、Scala的第一个例子:Hello World ##### 2.1 第一个Scala程序 ```scala object HelloWorld { def main(args: Array[String]) { println("Hello, world!") } } ``` - **`object`关键字**:在Scala中,`...