1.什么是函数式对象(functional object) ?
The emphasis in this chapter is on classes that define functional objects, that is, objects that do not have any mutable state.
状态不可变的对象
2. 对函数式对象的取舍(immutable object trade-offs)
Immutable objects offer several advantages over mutable objects, and
one potential disadvantage. First, immutable objects are often easier to
reason about than mutable ones, because they do not have complex state
spaces that change over time. Second, you can pass immutable objects
around quite freely, whereas you may need to make defensive copies
of mutable objects before passing them to other code. Third, there is
no way for two threads concurrently accessing an immutable to corrupt
its state once it has been properly constructed, because no thread can
change the state of an immutable. Fourth, immutable objects make safe
hash table keys. If a mutable object is mutated after it is placed into a
HashSet, for example, that object may not be found the next time you
look into the HashSet.
优点: 容易推理,自由传递,不用担心并发,作为哈希键更安全
The main disadvantage of immutable objects is that they sometimes
require that a large object graph be copied where otherwise an update
could be done in place. In some cases this can be awkward to express
and might also cause a performance bottleneck.
缺点: 复制对象有时代价太大,就地更改会更高效
3. 主构造函数(primary constructor)
class Rational (n: Int, d: Int)
4.
The Scala compiler will compile any code you place in the class body,
which isn’t part of a field or a method definition, into the primary constructor.
类body中,不属于属性和方法的代码,都会被编译到主构造函数中
class Rational (n: Int, d: Int) { print("created "+n+"/"+d) } object TestMain { def main(args: Array[String]) { val r = new Rational(2, 3) // created 2/3 } }
5. 重写默认的toString方法
override the default implementation of method toString
class Rational (n: Int, d: Int) { override def toString = n + "/" + d }
6. 检查先决条件
class Rational (n: Int, d: Int) { require(d != 0) override def toString = n + "/" + d } object TestMain{ def main(args: Array[String]) { val r = new Rational(2, 0) } } //console Exception in thread "main" java.lang.IllegalArgumentException: requirement failed at scala.Predef$.require(Predef.scala:207) at chapter6.Rational.<init>(Rational.scala:4) at chapter1.TestMain$.main(TestMain.scala:8) at chapter1.TestMain.main(TestMain.scala)
7 . 添加add方法
class Rational (n: Int, d: Int) { require(d != 0) override def toString = n + "/" + d def numer = n def denom = d def add(that: Rational) = new Rational(n * that.denom + d * that.numer, d * that.denom) }
8. 辅助构造函数(auxiliary constructor),私有方法
class Rational (n: Int, d: Int) { require(d != 0) def this(n: Int) = this(n, 1) override def toString = numer + "/" + denom def g = gcd(n, d) def numer = n / g def denom = d / g def add(that: Rational) = new Rational( this.numer * that.denom + this.denom * that.numer, d * that.denom) def lessThan(that: Rational) = this.numer * that.denom < this.denom * that.numer def max(that: Rational) = if (lessThan(that)) that else this private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) }
9.加法和乘法
class Rational (n: Int, d: Int) { require(d != 0) def this(n: Int) = this(n, 1) override def toString = numer + "/" + denom def g = gcd(n, d) def numer = n / g def denom = d / g def add(that: Rational) = new Rational( this.numer * that.denom + this.denom * that.numer, d * that.denom) def lessThan(that: Rational) = this.numer * that.denom < this.denom * that.numer def max(that: Rational) = if (lessThan(that)) that else this def + (that: Rational) = new Rational( this.numer * that.denom + this.denom * that.numer, this.denom * that.denom) def * (that: Rational) = new Rational( this.numer * that.numer, this.denom * that.denom) private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) } object TestMain{ def main(args: Array[String]) { val r1 = new Rational(49, 56) val r2 = new Rational(1, 2) val r3 = new Rational(1, 3) println(r1) // 7/8 println(r2) // 1/2 println(r1 + r2) // 11/8 println(r1 * r2) // 7/16 println(r1 + r2 * r3) // 25/24 } }
从最后一行输出可以看出,Scala会自动为 乘法和加法绑定默认的运算优先级
10 .重载 加法和乘法 添加减法和除法
def + (i: Int) = new Rational(numer + i * denom, denom) def * (i: Int) = new Rational(numer * i, denom) def - (that: Rational) = new Rational ( numer * that.denom - that.numer * denom, denom * that.denom) def - (i: Int) = new Rational ( numer - i * denom, denom) def / (that: Rational) = new Rational(numer * that.denom, denom * that.numer) def / (i: Int) = new Rational(numer, denom * i)
11. 隐式转换(implicit conversions)
object TestSheet { val r = new Rational(1, 2) //> r : chapter6.Rational = 1/2 r * 2 //> res0: chapter6.Rational = 1/1 2 * r // error here }
因为 Int 类型没有 定义接收一个Rational作为参数的乘法运算,所以出错。下面我们来定义一个隐式转换方法
object TestSheet { val r = new Rational(1, 2) //> r : chapter6.Rational = 1/2 implicit def intToRational(x: Int) = new Rational(x) //> intToRational: (x: Int)chapter6.Rational r * 2 //> res0: chapter6.Rational = 1/1 2 * r //> res1: chapter6.Rational = 1/1 }
编译器自动查找上下文中所有用implicit修饰的方法,如果恰好有一个以Int为输入类型,Rational为返回类型,则自动将该方法用于需要转换的对象上
一言以蔽之: 出现在什么类型的位置上,就试图转换为什么类型。 Scala编译器能做到这一点实在是了不起。