Scala学习(二)——高级特性
apply() 方法
apply方法是Scala提供的一个语法糖
类名+括号,调用对象的apply方法
对象名+括号,调用类的apply方法
对apply方法的简单测试:(其中,带 new -- class ApplyTest,不带 new -- object ApplyTest)
class ApplyTest {
println("class ApplyTest")
def apply() {
println("class APPLY method")
}
}
object ApplyTest {
println("object ApplyTest")
def apply() = {
println("object APPLY method")
new ApplyTest()
}
}
// 对象名+括号,调用类的apply方法
val a1 = new ApplyTest()
a1() // == a1.apply()
// 输出 class ApplyTest, class APPLY method
// 类名+括号,调用对象的apply方法
val a2 = ApplyTest()
// 输出 object ApplyTest, object APPLY method, class ApplyTest
val a2 = ApplyTest()
a2()
// 输出 object ApplyTest, object APPLY method, class ApplyTest, class APPLY method
val a3 = ApplyTest
// 输出 object ApplyTest
val a3 = ApplyTest
a3()
// 输出 object ApplyTest, object APPLY method, class ApplyTest
单例对象
单例对象用于持有一个类的唯一实例。通常用于工厂模式。
object Timer {
var count = 0
def currentCount(): Long = {
count += 1
count
}
}
可以这样使用:
Timer.currentCount() //1
单例对象可以和类具有相同的名称,此时该对象也被称为“伴生对象”。我们通常将伴生对象作为工厂使用。
下面是一个简单的例子,可以不需要使用’new’来创建一个实例了。
class Bar(foo: String)
object Bar {
def apply(foo: String) = new Bar(foo)
}
函数即对象
在Scala中,我们经常谈论对象的函数式编程。这是什么意思?到底什么是函数呢?
函数是一些特质的集合。具体来说,具有一个参数的函数是Function1特质的一个实例。这个特质定义了apply()语法糖,让你调用一个对象时就像你在调用一个函数。
object addOne extends Function1[Int, Int] {
def apply(m: Int): Int = m + 1
}
addOne(1) // 2
这个Function特质集合下标从0开始一直到22。为什么是22?这是一个主观的魔幻数字(magic number)。我从来没有使用过多于22个参数的函数,所以这个数字似乎是合理的。
apply语法糖有助于统一对象和函数式编程的二重性。你可以传递类,并把它们当做函数使用,而函数本质上是类的实例。
这是否意味着,当你在类中定义一个方法时,得到的实际上是一个Function*的实例?不是的,在类中定义的方法是方法而不是函数。在repl中独立定义的方法是Function*的实例。
类也可以扩展Function,这些类的实例可以使用()调用。
class AddOne extends Function1[Int, Int] {
def apply(m: Int): Int = m + 1
}
val plusOne = new AddOne()
plusOne(1) //2
可以使用更直观快捷的extends (Int => Int)代替extends Function1[Int, Int]
class AddOne extends (Int => Int) {
def apply(m: Int): Int = m + 1
}
模式匹配
这是Scala中最有用的部分之一。
匹配值
val times = 1
times match {
case 1 => "one"
case 2 => "two"
case _ => "some other number"
}
使用守卫进行匹配
times match {
case i if i == 1 => "one"
case i if i == 2 => "two"
case _ => "some other number"
}
注意我们是怎样获取变量’i’的值的。
在最后一行指令中的_是一个通配符;它保证了我们可以处理所有的情况。 否则当传进一个不能被匹配的数字的时候,你将获得一个运行时错误。
匹配类型
你可以使用 match来分别处理不同类型的值。
def bigger(o: Any): Any = {
o match {
case i: Int if i < 0 => i - 1
case i: Int => i + 1
case d: Double if d < 0.0 => d - 0.1
case d: Double => d + 0.1
case text: String => text + "s"
}
}
匹配类成员
定义一个计算器,让我们通过类型对它们进行分类。
def calcType(calc: Calculator) = calc match {
case _ if calc.brand == "HP" && calc.model == "20B" => "financial"
case _ if calc.brand == "HP" && calc.model == "48G" => "scientific"
case _ if calc.brand == "HP" && calc.model == "30B" => "business"
case _ => "unknown"
}
样本类 Case Classes
使用样本类可以方便得存储和匹配类的内容。不用new关键字就可以创建它们。
case class Calculator(brand: String, model: String)
val hp20b = Calculator("HP", "20b")
样本类基于构造函数的参数,自动地实现了相等性和易读的toString方法。
val hp20b = Calculator("HP", "20b")
val hp20B = Calculator("HP", "20b")
hp20b == hp20B // true
样本类也可以像普通类那样拥有方法。
使用样本类进行模式匹配
样本类就是被设计用在模式匹配中的。让我们简化之前的计算器分类器的例子。
val hp20b = Calculator("HP", "20B")
val hp30b = Calculator("HP", "30B")
def calcType(calc: Calculator) = calc match {
case Calculator("HP", "20B") => "financial"
case Calculator("HP", "48G") => "scientific"
case Calculator("HP", "30B") => "business"
case Calculator(ourBrand, ourModel) => "Calculator: %s %s is of unknown type".format(ourBrand, ourModel)
}
最后一句也可以这样写
case Calculator(_, _) => "Calculator of unknown type"
或者我们完全可以不将匹配对象指定为Calculator类型
case _ => "Calculator of unknown type"
或者我们也可以将匹配的值重新命名。
case c@Calculator(_, _) => "Calculator: %s of unknown type".format(c)
本文主要参考自Scala School-基础知识(续)
Scala学习(二)——高级特性的更多相关文章
- 大数据笔记(二十六)——Scala语言的高级特性
===================== Scala语言的高级特性 ========================一.Scala的集合 1.可变集合mutable 不可变集合immutable / ...
- Scala学习(二)--- 控制结构和函数
控制结构和函数 摘要: 本篇主要学习在Scala中使用条件表达式.循环和函数,你会看到Scala和其他编程语言之间一个根本性的差异.在Java或C++中,我们把表达式(比如3+4)和语句(比如if语句 ...
- Scala学习二——控制结构和函数
一.if表达式有值 val s=if(x>0) 1 else -1,相当于Java中x>0?1:-1(不过不拿呢个在?:中插入语句),而且Scala中可以用混合类型(如if (x>0 ...
- php面向对象编程学习之高级特性
前几天写了一篇关于php面向对象基础知识的博客,这两天看了php面向对象的高级特性,写出来记录一下吧,方便以后拿出来复习. 面向对象除了最基本的定义类之外,最主要就是因为面向的一些高级特性,运用这些高 ...
- Scala学习——函数高级操作
scala函数高级操作 一.字符串高级操作 多行字符串和插值 package top.ruandb.scala.Course06 object StringApp { def main(args: A ...
- Scala学习二十二——定界延续
一.本章要点 延续让你可以回到程序执行当中之前的某个点; 可以在shift块中捕获延续 延续函数一直延展到包含它的reset块的尾部 延续所谓的”余下的运算“,从包含shift的表达式开始,到包含它的 ...
- Scala学习二十一——隐式转换和隐式参数
一.本章要点 隐式转换用于类型之间的转换 必须引入隐式转换,并确保它们可以以单个标识符的形式出现在当前作用域 隐式参数列表会要求指定类型的对象.它们可以从当前作用域中以单个标识符定义的隐式对象的获取, ...
- Scala学习二十——Actor
一.本章要点 每个actor都要扩展Actor类并提供act方法 要往actor发送消息,可以用actor!message 消息发送是异步的:”发完就忘“ 要接受消息,actor可以调用receive ...
- Scala学习(二)练习
Scala控制结构和函数&练习 1. 一个数字如果为正数,则它的signum为1:如果是负数,则signum为-1:如果为0,则signum为0:编写一个函数来计算这个值 简单逻辑判断: 测试 ...
- Python学习之高级特性
切片 在Python基础篇里,我们知道Python的可序列对象可以通过索引号(下标)来引用对象元素,索引号可以由0开始从左向右依次获取,可以从-1开始由右向左获取.这种方法可以帮助我们依次获取我们想要 ...
随机推荐
- linux下vim常用命令 (更新中...)
1.注释多行 1). 首先按esc进入命令行模式下,按下Ctrl + v,进入VISUAL BLOCK模式; 2). 在行首使用上下键选择需要注释的多行; 3). 按下键盘(大写)“I”键,进入插入模 ...
- Delphi 变量的作用域
- linux基本操作和常用命令(2)
linux基本操作和常用命令(2) 第二部分主要是涉及到用户和组的概念,以及一些操作.涉及到用户和组的共三个文件,分别存放在/etc/shadow(密码信息) /etc/group(组信息) /etc ...
- LCD 原理和移植总结【转】
转自:http://blog.chinaunix.net/uid-22915173-id-329617.html Framebuffer:是linux的framebuffer驱动在内存开辟的一块显存, ...
- 简单了解 TCP TCP/IP HTTP HTTPS
一. 什么是TCP连接的三次握手 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认: 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+ ...
- Jenkins 入门系列--jenkins 介绍
第一章 Jenkins是什么? Jenkins 是一个可扩展的持续集成引擎. 主要用于: l 持续.自动地构建/测试软件项目. l 监控一些定时执行的任务. Jenkins拥有的特性包括: l 易于安 ...
- 清北学堂dp图论营游记day4
依然zhx讲. 讲了概率与期望: 期望:事件结果的平均大小.记作E(x). E(x)=每种结果的大小与其概率的乘积的和. 例如,记掷一枚骰子的点数为x E(x)=1*(1/6)+2*(1/6)+3*( ...
- 区块链——java实现
简述 本文主要的内容试一次关于区块链的作业,本次作业中有很多地方和实际的区块链不符合,比如hash,本文实现的区块链只是用了区块本身的hash并没去区分,头部和数据部分.仅供参考学习. 介绍 内容有点 ...
- poj3208 Apocalypse Someday[数位DP]
数位中出现至少3个连续的'6'的数字(称魔鬼数),询问满足要求的排名k的数. 经典题型.采用试填法. 递推做法:预处理出$i$位数字中满足要求的数(下记为'魔鬼数').对每一位都从0到9试一遍,然而卡 ...
- Mac的MySQL无法启动的原因
一.由于Mac OS X的升级或其他原因可能会导致一个错误: Warning:The /usr/local/mysql/data directory is not owned by the 'mysq ...