`

Scala基础(二)

 
阅读更多

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基础知识文档

    #### 二、Scala基础语法 ##### 1. 声明值和变量 Scala中的值和变量可以通过`val`和`var`关键字进行声明: - `val`: 定义一个不可变的值(即常量)。 - `var`: 定义一个可变的变量。 ```scala val num = 0 var ...

    快学Scala第二版(英文)(2016年版)

    首先,书中会介绍Scala的基础语法,包括变量、常量、表达式和控制流。Scala的变量声明不同于传统的静态类型语言,它支持类型推断,使得代码更简洁。同时,Scala的控制流结构,如if-else、while和for循环,也比Java等...

    Scala基础语法课件汇总整本书电子教案全套课件完整版ppt最新教学教程.pptx

    Scala 于 2003 年底 /2004 年初发布,第二个版本 v2.0 发布于 2006 年 3 月。 Scala 的特性 Scala 的关键特性包括: * 面向对象特性 * 支持命令式风格和函数式风格 * 自适应静态类型 * 简洁性 * 基于事件的并发...

    about云spark开发基础之Scala快餐第二版.pdf

    ### 关于《云Spark开发基础之Scala快餐第二版》的知识点提炼 #### 一、Scala与函数式编程 - **Scala的特点**: - **语言背景**:Scala是一种结合了面向对象编程和函数式编程特点的多范式编程语言。由于Spark的...

    scala编程 第二版(高清+书签)

    Scala编程第二版是一本深受读者喜爱的编程指南,豆瓣评分高达8.0,这足以证明其在编程领域的权威性和实用性。Scala是一种多范式编程语言,融合了面向对象和函数式编程的特点,使得它在处理大数据和分布式计算时,如...

    快学 Scala(第二版) Second Edition

    **Scala基础知识** 1. **类型系统**:Scala拥有强类型系统,类型推断机制使代码更简洁。例如,变量定义时可以省略类型,编译器会自动推断。 2. **对象和类**:Scala将面向对象编程中的类和对象紧密结合。任何东西...

    scala编程基础

    #### 三、Scala基础语法 **声明变量**: Scala支持多种类型的变量声明方式,如`val`用于声明不可变变量,`var`用于声明可变变量。 **常用类型**: Scala支持各种内置类型,如整型(`Int`)、浮点型(`Double`)、...

    Scala程序设计第二版

    1. **Scala基础**:首先,书本会介绍Scala的基本语法,如变量定义、数据类型(包括基本类型和复杂类型如数组和集合)、控制结构(如if-else、for循环和while循环)、函数和方法等。 2. **面向对象编程**:Scala是...

    Scala.pdf中文高清第二版

    通过学习《Scala.pdf中文高清第二版》,初学者将能够掌握Scala的基本用法和高级特性,为从事现代软件开发打下坚实基础。这本书的高清版意味着阅读体验更佳,有助于深入理解和掌握每一个知识点。

    Scala语法简明教程

    #### Scala基础语法 - **变量声明**: - Scala中声明变量使用`val`(用于不可变变量)或`var`(用于可变变量)。与Java相比,Scala更简洁,例如,`var age = 28`。 - **常量声明**: - 使用`val`关键字声明常量...

    Programming in Scala 2nd Edition

    ### 编程在Scala:第二版 #### 书籍概述 《Programming in Scala》第二版是一本全面详尽的Scala编程指南,由Scala语言的主要设计者Martin Odersky、Lex Spoon和Bill Venners共同撰写。本书是为Scala 2.8版本更新的...

    大数据课程-Scala编程基础-3.Scala面对对象的特性_lk_edit.ppt

    第二种风格是通过嵌套来表示层级关系,一个源文件可以声明多个包,子包中的类可以直接访问父包的内容,无需显式导入。 此外,Scala还支持包对象,它是包下所有类和对象的共享变量,可以直接访问。包对象可以通过`...

    快学scala习题及答案详解

    描述中提到的三份文档——"快学scala第一章习题答案.doc"、"快学scala第二章习题答案.doc"、"快学scala第三章习题答案.doc"——暗示了这份学习资料是按照章节结构编排的,每个章节都有对应的习题和详尽的答案。...

    快学scala第二版本示例代码

    "快学Scala第二版本示例代码" 提供了一种系统性的学习途径,帮助开发者深入理解Scala的核心概念和实践应用。 首先,从文件名列表来看,我们可以看到一系列按照章节组织的代码示例,比如`ch20`到`ch03`。这暗示了...

    大数据-Scala编程基础_教学指导

    在课程内容上,Scala编程基础分为三个模块: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中,`...

Global site tag (gtag.js) - Google Analytics