Scala实践3
一、函数式对象
1.1 rational类的规格和创建
- Rational类来源于有理数(rational number),来表示n(分子)/d(分母)的数字,同时对有理数的运算(加减乘除)建模,还具备归元化的特点。
下例子没有建模的:
scala> val oneHalf=new Rational(1,2)
oneHalf: Rational = 1/2
scala> val twoThirds=new Rational(2,3)
twoThirds: Rational = 2/3
scala> (oneHalf /7)+(1 twoThirds)
<console>:13: error: value / is not a member of Rational
(oneHalf /7)+(1 twoThirds)
^
<console>:13: error: value twoThirds is not a member of Int
(oneHalf /7)+(1 twoThirds)
scala> (oneHalf /7)+1
<console>:13: error: value / is not a member of Rational
(oneHalf /7)+1
- Rational的创建,类名后的括号里的n、d两个类参数。Scala编译器会收集这两个类参数并创造出带同样的参数的主构造器。
Class Rational(n:Int,d:Int)
scala> class Rational(n:Int,d:Int){
| println("Created"+n+"/"+d)
| }
defined class Rational scala> new Rational(1,2)
Created1/2
res21: Rational = Rational@6fbfd6ed
默认情况下,Rational类继承了java.lang.Object类的toString实现,只会打印类名、@和十六进制数。
- 为了打印出具体的分子分母,可以通过重载Rational类的toString实现。
scala> class Rational(n:Int,d:Int){
| override def toString = n+"/"+d }
defined class Rational
scala> val x =new Rational(1,3)
x: Rational = 1/3
1.2 rational先决条件
面向对象编程的优点之一是它允许你将数据封装在对象之内以确保数据在整个生命周期中的有效性。意味着必须确保rational类建有理数的有效性,
即分母不为0,故应该为主构造器定义一个先决的条件,说明d不为0,先决条件是对传递给方法或者构造器的值的限制,是调用者必须满足的需求。
- 一种方法是使用require方法,如:
scala> class Rational(n:Int,d:Int){
| require(d!=0)
| override def toString = n+"/"+d
| }
defined class Rational
scala> new Rational(2,0)
java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:268)
... 29 elided
scala> new Rational(2,9)
res13: Rational = 2/9
注:Require方法带来一个布尔型参数。如果传入的值为真,require将正常返回,反之,require将抛出IllegalArgumentException防止对象被构建。
1.3 添加字段
为了保持Rational的不可变性,add方法不能把传入的有理数加到自己身上,而是必须创建并返回全薪的Rational累加值。
class Rational(n:Int,d:Int){
require(d!=0)
val number:Int=n
val denom:Int=d
override def toString =number + "/"+denom
def add(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
}
scala>val oneHalf=new Rational(1,2)
oneHalf: Rational = 1/2
1.4 自指向this
关键字this指向当前执行方法被调用的对象实例,或者如果使用在构造器里的话,就是正被构建的对象实例。如下:
scala> class Rational(n:Int,d:Int){
| require(d!=0)
| val number:Int=n
| val denom:Int=d
| override def toString =number + "/"+denom
| def add(that:Rational):Rational=
| new Rational(
| number*that.denom+that.number*denom,
| denom*that.denom
| )
| def lessThan(that:Rational)=this.number*that.denom<that.number*this.denom
| def max(that:Rational)=if(this.lessThan(that)) that else this
| }
defined class Rational
scala> new Rational(1,2)
res42: Rational = 1/2
scala> new Rational(1,4)
res43: Rational = 1/4
scala> res43.lessThan(res42)
res44: Boolean = true
scala> res43.max(res42)
res45: Rational = 1/2
1.5 辅助构造器
- Scala里主构造器之外的构造器被称为辅助构造器。作用:对5/1,能够写成Rational(5),这就需要给Rational添加辅助构造器预先设置分母为1
class Rational(n:Int,d:Int){
require(d!=0)
val number:Int=n
val denom:Int=d
def this(n:Int) =this(n,1)//辅助构造器
override def toString =number + "/"+denom
def add(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
}
1.6 私有字段和方法
- 为了约简化(归元化)为无差别的最简形式,即(66/42---->11/7),引入私有的最大公约数的字段和方法。
class Rational(n:Int,d:Int){
require(d!=0)
private val g =gcd(n.abs,d.abs)
val number=n/g
val denom=d/g
def this(n:Int) =this(n,1)
def add(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
override def toString =number + "/"+denom
private def gcd(a:Int,b:Int):Int =
if(b==0) a else gcd(b,a%b)
}
scala> new Rational(99,66)
res23: Rational = 3/2
17. 定义操作符
在Scala中用常用的数学符号+替换add方法,因为Scala里+是合法的标识符,能够用+定义方法名。
class Rational(n:Int,d:Int){
require(d!=0)
private val g =gcd(n.abs,d.abs)
val number=n/g
val denom=d/g
def this(n:Int) =this(n,1)
def +(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
override def toString =number + "/"+denom
private def gcd(a:Int,b:Int):Int =
if(b==0) a else gcd(b,a%b)
}
结果如下:
scala> new Rational(4,9)
res30: Rational = 4/9
scala> new Rational(4,8)
res31: Rational = 1/2
scala> res30+res31
res32: Rational = 17/18
1.8. 方法重载
在上面定义的都是有理数的运算,引入整数和有理数之间的运算,使用方法重载。
class Rational(n:Int,d:Int){
require(d!=0)
private val g =gcd(n.abs,d.abs)
val number=n/g
val denom=d/g
def this(n:Int) =this(n,1)
def +(that:Rational):Rational=
new Rational(
number*that.denom+that.number*denom,
denom*that.denom
)
def +(i:Int):Rational=
new Rational(
number+i*denom,denom
)
override def toString =number + "/"+denom
private def gcd(a:Int,b:Int):Int =
if(b==0) a else gcd(b,a%b)
}
结果如下:
scala> new Rational(1,2)
res37: Rational = 1/2
scala> 2
res38: Int = 2
scala> res37+res38
res39: Rational = 5/2
Scala实践3的更多相关文章
- Scala实践14
1.Scala的future 创建future import scala.concurrent._ import ExecutionContext.Implicits.global object Fu ...
- Scala实践13
1.隐式参数 方法可以具有隐式参数列表,由参数列表开头的implicit关键字标记.如果该参数列表中的参数没有像往常一样传递,Scala将查看它是否可以获得正确类型的隐式值,如果可以,则自动传递. S ...
- Scala实践12
1.内部类和抽象类型成员作为对象成员 内部类 在Scala中,可以让类将其他类作为成员.这些内部类是封闭类的成员.在Scala中,这样的内部类绑定到外部对象.假设希望编译器在编译时阻止我们混合哪些节点 ...
- Scala实践11
1.1泛型类 泛型类是将类型作为参数的类.它们对集合类特别有用. 定义泛类型:泛型类将类型作为方括号内的参数[].一种惯例是使用字母A作为类型参数标识符,但是可以使用任何参数名称. class Sta ...
- Scala实践10
1.模式匹配 模式匹配是一种根据模式检查值的机制.它是switch(Java中语句)的更强大版本,它同样可以用来代替一系列if / else语句. 句法 匹配表达式具有值,match关键字和至少一个c ...
- Scala实践9
1.特征 Traits用于在类之间共享接口和字段.它们类似于Java 8的接口.类和对象可以扩展特征,但是特征不能被实例化,因此没有参数. 定义一个特征 最小特征只是关键字trait和标识符: tra ...
- Scala实践6
1 if表达式 Scala中if...else..表达式是有返回值的,如果if和else返回值类型不一样,则返回Any类型. scala> val a3=10 a3: Int = 10 sca ...
- Scala实践8
1.1继承类 使用extends关键字,在定义中给出子类需要而超类没有的字段和方法,或者重写超类的方法. class Person { var name = "zhangsan" ...
- Scala实践7
一.类 1.1简单类和无参方法 类的定义通过class关键字实现 scala> class Dog { | private var leg = 4 | def shout(content: St ...
- Scala实践5
一.Scala的层级 1.1类层级 Scala中,Any是所其他类的超类,在底端定义了一些有趣的类NULL和Nothing,是所有其他类的子类. 根类Any有两个子类:AnyVal和AnyRef.其中 ...
随机推荐
- Group_concat介绍与例子
进公司做的第一个项目就是做一个订单追踪查询,里里外外连接了十一个表,作为公司菜鸡的我麻了爪. 其中有一个需求就是对于多行的数据在一行显示,原谅我才疏学浅 无奈下找到了项目组长 在那学来了这个利器 ( ...
- Python--day65--模板语言之tags
Tags for循环 普通for循环 <ul> {% for user in user_list %} <li>{{ user.name }}</li> {% en ...
- [转载] linux find 命令
转载自 http://www.jb51.net/os/RedHat/1307.html Linux下find命令在目录结构中搜索文件,并执行指定的操作. Linux下find命令提供了相当多的查找条件 ...
- servicemix-3.2.1 部署异常
<jbi-task xmlns="http://java.sun.com/xml/ns/jbi/management-message" version="1.0&q ...
- JPA进行insert操作时会首先select吗
在某个项目中,使用JPA的saveAll方法去批量写入数据时,通过打印sql,发现每次insert前都会先select一次,极大的浪费了写入性能. 分析一下代码,saveAll() @Transact ...
- 日历价差(calendar spread)
日历价差(calendar spread) 是指投资者买进到期日较远的期权 (简称远期期权),同时又卖出相同行权价格.相同数量但到期日较近的期权(简称近期期权),赚取两个不同期权隐含波动率的差价或者其 ...
- js 页面分享
首先说分享到QQ空间的通用代码:<a href="javascript:void(0);" onclick="window.open('http://sns.qzo ...
- 2019-10-23-WPF-使用-SharpDx-异步渲染
title author date CreateTime categories WPF 使用 SharpDx 异步渲染 lindexi 2019-10-23 21:18:38 +0800 2018-0 ...
- Vue的事件修饰符
转载于:https://www.cnblogs.com/xuqp/p/9406971.html 事件处理 如果需要在内联语句处理器中访问原生DOM事件.可以使用特殊变量$event,把它传入到meth ...
- UVA 11212 Editing a Book [迭代加深搜索IDA*]
11212 Editing a Book You have n equal-length paragraphs numbered 1 to n. Now you want to arrange the ...