Programming in Scala (Second Edition) 读书笔记6 函数式对象

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编译器能做到这一点实在是了不起。

时间: 2024-10-12 09:48:37

Programming in Scala (Second Edition) 读书笔记6 函数式对象的相关文章

Programming in Scala (Second Edition) 读书笔记18 Stateful Object

1. In previous chapters, we put the spotlight on functional (immutable) objects 在前面的章节,我们把焦点放在了函数式对象上 We did so because the idea of objects without any mutable state deserves to be better known 函数式对象更容易被理解,它永远只有一种状态 However, it is also perfectly poss

Programming in Scala (Second Edition) 读书笔记21 隐式转化

1. There's a fundamental difference between your own code and libraries of other people: you can change or extend your own code as you wish, but if you want to use someone else's libraries, you usually have to take them as they are. 你可以改变或扩展自己的代码,但是对

Programming in Scala (Second Edition) 读书笔记13 packages and import

目前,在一个包中你看到的top level的对象只有:class, trait, object.其实任何对象都可以是top level的.也就是说,没有必要把函数,value, variable等限制在class, trait, object中.它们可以在整个包范围内都是全局性的. 方法很简单,把这些东东放到package object中就行了.pakcage object的名字和包名相同 包含package object的文件放在该packag下,名字就叫package.scala chapt

Programming in Scala (Second Edition) 读书笔记12 Trais

1.什么是Trait ? Traits are a fundamental unit of code reuse in Scala. A trait encapsulatesmethod and field definitions, which can then be reused by mixing them intoclasses. Unlike class inheritance, in which each class must inherit from justone supercla

Programming in Scala (Second Edition) 读书笔记15 case class and pattern matching

一个算术表达式包含: 数字,变量,二元操作符,一元操作符.用下面几个类来模拟它们 package chapter15 abstract class Expr case class Var(name: String) extends Expr case class Number(num: Double) extends Expr case class UnOp(operator: String, arg: Expr) extends Expr case class BinOp(operator: 

Programming in Scala (Second Edition) 读书笔记10

你肯定见过在控制台用字符打印图形的程序,这一章就从定义一个图形元素开始.我们的图形元素都是一些字符组成的矩形 abstract class Element {   def contents: Array[String]   def height: Int = contents.length   def width: Int = if (height == 0) 0 else contents(0).length } 上面定义的三个方法都没有参数,连小括号也省去了.这样的方法叫做:无参方法(par

Programming in Scala (Second Edition) 读书笔记6 函数和闭包

When programs get larger, you need some way to divide them into smaller, more manageable pieces. For dividing up control flow, Scala offers an approach familiar to all experienced programmers: divide the code into functions. In fact, Scala offers sev

Programming in Scala (Second Edition) 读书笔记7 内置控制结构

1. One thing you will notice is that almost all of Scala's control structures result in some value Scala的每种控制语句都是有值的 This is the approach taken by functional languages, in which programs are viewed as computing a value, thus the components of a progr

Programming in Scala (Second Edition) 读书笔记26 Extractors

1. By now you have probably grown accustomed to the concise way data can be decomposed and analyzed using pattern matching. This chapter shows you how to generalize this concept further. Until now, constructor patterns were linked to case classes. Fo