Scala 基础(5)—— 构建函数式对象
有了 Scala 基础(4)—— 类和对象 的前提,现在就可以来构建一个基于 Scala 的函数式对象。
下面开始构造一个有理数对象 Rational。
1. 主构造方法和辅助构造方法
对于每一个类的定义,Scala 只允许一个主构造方法,主构造方法的入参紧跟在类定义的后面:
class Rational(n: Int, d: Int) { } val r = new Rational(1,2) // 有理数 1/2
你可能需要一个分母 d 被预定义为 1 的一个构造方法,这事就需要用到辅助构造方法(auxiliary constructor)。
辅助构造方法以 def this(...) 开始:
class Rational(n: Int, d: Int) { def this(n: Int) = this(n, 1)
} val r = new Rational(5) // 有理数5
2. 前置条件
你可能需要对初始化一个对象进行一些参数检查,例如有理数的分母 d 不能为 0。
在每一个 Scala 文件中都会自动引用 Predef 这个独立对象,里面有 require() 方法能够满足这个需求。
class Rational(n: Int, d: Int) {
require(d != 0)
def this(n: Int) = this(n, 1)
} val r = new Rational(5, 0) // 会抛出异常
3. toString() 方法
对于一个类来说,重写 toString() 方法是一个很常见的需求。
需要注意的是 Scala 对于重写父类方法,会强制加上 override,而在 Java 中这一行为是 optional 的。
class Rational(n: Int, d: Int) {
require(d != 0)
def this(n: Int) = this(n, 1)
override def toString: String = n + "/" + d // 去掉 override 会编译报错
}
4. 添加字段和方法
在这里为 Rational 类添加一个 add() 方法,这里会出现一个初学者常见的错误:
class Rational(n: Int, d: Int) {
require(d != 0) def this(n: Int) = this(n, 1) override def toString: String = n + "/" + d def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d)
}
这段逻辑看似没有问题,而且编译期间也不会报错,但是运行时却会报错。
原因在于,虽然当前对象 this 可以很自然地使用构造方法传入的 n 和 d,但是 that 对象却不能这么使用。
这时就要增加字段:
class Rational(n: Int, d: Int) {
require(d != 0) val numer: Int = n
val denom: Int = d def this(n: Int) = this(n, 1) override def toString: String = n + "/" + d def add(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)
}
对于有理数来说,我们不希望出现 2/10 这样的数字,而是 1/5,这时就要增加私有的方法 gcd 来求最大公约数,以及私有字段 g 存储最大公约数:
class Rational(n: Int, d: Int) {
require(d != 0) private val g = gcd(n.abs, d.abs)
val numer: Int = n / g
val denom: Int = d / g def this(n: Int) = this(n, 1) override def toString: String = numer + "/" + denom def add(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom) private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
}
5. 定义操作符
Scala 可以用定义方法同样的方式定义操作符,达到类似“操作符重载”的效果。
例如,add 方法可以用 + 操作符代替:
class Rational(n: Int, d: Int) {
require(d != 0) private val g = gcd(n.abs, d.abs)
val numer: Int = n / g
val denom: Int = d / g def this(n: Int) = this(n, 1) override def toString: String = numer + "/" + denom def +(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom) private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
} val r1 = new Rational(5, 10)
val r2 = new Rational(3, 10)
println(r1 + r2) // 可以用+操作符,结果是 4/5
由此处可见,Scala 中的标识符分为2种:
- 字母数字组合标识符:规则基本与 Java 相同,推荐驼峰命名法。
- 操作标识符:由一个或多个操作字符构成。
6. 方法重载
与 Java 相同,Scala 支持相同方法名,不同的参数列表的方法重载:
class Rational(n: Int, d: Int) {
require(d != 0) private val g = gcd(n.abs, d.abs)
val numer: Int = n / g
val denom: Int = d / g def this(n: Int) = this(n, 1) override def toString: String = numer + "/" + denom def +(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom) def +(that: Int): Rational = new Rational(numer + that * denom, denom) private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
}
Scala 基础(5)—— 构建函数式对象的更多相关文章
- Scala基础:面向对象之对象和继承
对象 object 相当于 class 的单个实例,通常在里面放一些静态的 field 或者 method:在 Scala 中没有静态方法和静态字段,但是可以使用 object 这个语法结构来达到同样 ...
- Scala编程--函数式对象
本章的重点在于定义函数式对象,也就是说,没有任何可变状态的对象的类.作为运行的例子,我们将创造若干把分数作为不可变对象建模的类的变体.在这过程中,我们会展示给你Scala面向对象编程的更多方面:类参数 ...
- scala函数式编程(二) scala基础语法介绍
上次我们介绍了函数式编程的好处,并使用scala写了一个小小的例子帮助大家理解,从这里开始我将真正开始介绍scala编程的一些内容. 这里会先重点介绍scala的一些语法.当然,这里是假设你有一些ja ...
- Scala学习笔记——函数式对象
用创建一个函数式对象(类Rational)的过程来说明 类Rational是一种表示有理数(Rational number)的类 package com.scala.first /** * Creat ...
- scala编程(六)——函数式对象
Rational 的式样书 分数:rational number 是一种可以表达为比率 d n 的数字,这里的 n 和 d 是数字,其中 d 不能为零.n 被称作是分子:numerator,d 被称作 ...
- Scala 基础(二):sbt介绍与构建Scala项目
一.sbt简介 sbt是类似ANT.MAVEN的构建工具,全称为Simple build tool,是Scala事实上的标准构建工具. 主要特性: 原生支持编译Scala代码和与诸多Scala测试框架 ...
- 1.scala基础语法总结
Scala基础语法总结:Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的.如果一行里写多个语句那么分号是需要的 val s = "菜鸟教程"; pr ...
- Scala基础简述
* Scala基础简述 本文章作为Scala快速学习的教程,前提环境是:我假设在此之前,你已经学会了Java编程语言,并且我们以随学随用为目标(在此不会深度挖掘探讨Scala更高级层次的知识).其中语 ...
- 第一章 Scala基础篇
目录 一.Scala基础语法 (一) 变量.类型.操作符 1.变量申明 2.字符串 3.数据类型 4.操作符 (二)循环判断 1.块表达式 2.条件表达式 3.循环表达式 (三)方法和函数 1.方法 ...
随机推荐
- 8、SpringBoot+Mybatis整合------参数取值方式
前言: 我们知道,在mybatis中,参数取值方式有两种: #{ } 和 ${ } 下面,我们来探讨下#{ }与${ }不同. 一.#{ } 例: select * from student wher ...
- 精心收集的48个JavaScript代码片段,仅需30秒就可理解
源文链接 :https://github.com/Chalarangelo/30-seconds-of-code#anagrams-of-string-with-duplicates 该项目来自于 G ...
- 安装破解IDEA(个人使用)
安装的过程,许多的教程都会有,我在这里附上一两个链接吧:https://blog.csdn.net/newabcc/article/details/80601933 他这里也有破解过程,但是比较麻烦, ...
- 记一次samba排错 Failed to start Samba SMB Daemon.
记录一次服务出错排错的过程,很多新手出了点错不百度直接巴拉巴拉的问,一般老手根据经验可以给出一点建议,但是由于个体环境的差异并不适用,反而埋怨起来.这种真的无F**K可说,所以要培养自己的排错能 ...
- 【转载】C#批量插入数据到Sqlserver中的三种方式
引用:https://m.jb51.net/show/99543 这篇文章主要为大家详细介绍了C#批量插入数据到Sqlserver中的三种方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本篇, ...
- linux 源码安装php7.0 yum
PHP7和HHVM比较PHP7的在真实场景的性能确实已经和HHVM相当, 在一些场景甚至超过了HHVM.HHVM的运维复杂, 是多线程模型, 这就代表着如果一个线程导致crash了, 那么整个服务就挂 ...
- MyFirstDay(附6篇python亲历面试题)
一直以来都是在看别人写的内容,学习前辈们的经验,总感觉自己好像没有什么值得拿出来分享和交流的知识,最近在准备换工作(python后端开发),坐标上海,2019年3月,半个月面了6家(感觉效率是真不高. ...
- C语言数组篇(四)二维数组
二维数组声明: ][] ={{,,},{,,}; //两行 三列 二维数组在声明的时候可以不写行,但一定要写列 ] = {{,},{,,},{}}; //未声明的地方自动补零 二维 ...
- C# 输出结果有System.Byte[]
byte[]类型直接输出或者调用ToString函数都会出现这个结果. 需要执行: byte[] a=new byte[10]; string text = "";for (int ...
- PTA 7-10(图) 旅游规划 最短路问题
7-10(图) 旅游规划 (25 分) 有了一张自驾旅游路线图,你会知道城市间的高速公路长度.以及该公路要收取的过路费.现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径.如果 ...