コップ本をやる 第6章 関数型スタイルのオブジェクト

この章ではイミュータブルなクラスを作成する方法を学びます。
作成するクラスは有理数(分数)を表すRationalクラスです。

// nとdはクラスパラメータで、その二つを取る基本コンストラクタ
class Rational(n: Int, d: Int) {

  // 事前条件を指定する
  // 事前条件に違反する場合IllegalArgumentExceptionを投げる。
  require(d != 0)

  // フィールド、メソッド定義以外を基本コンストラクタとしてコンパイルする
  private val g = gcd(n.abs, d.abs)

  // フィールド定義
  val numer: Int = n / g
  val denom: Int = d / g

  // 補助コンストラクタ
  // Scalaの補助コンストラクタでは、最初の処理で同じクラスの他のコンストラクタを呼ぶ必要がある
  def this(n: Int) = this(n, 1)

  // オーバーライドする際はメソッド定義にoverride修飾子を付ける
  override def toString = n + "/" + d

  // 有理数の加算
  def + (that: Rational): Rational =
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom)

  // 有理数の乗算
  def * (that: Rational): Rational =
    new Rational(
      numer * that.numer, denom * that.denom)

  // メソッドの多重定義
  def * (i: Int): Rational =
    new Rational(numer * i, denom)

  // thisで自己参照する
  def lessThan(that: Rational) =
    this.numer * that.denom < that.numer * this.denom

  // 非公開のメソッド
  private def gcd(a: Int, b: Int): Int =
    if (b == 0) a else gcd(b, a % b)
}

object Main {
  def main(args: Array[String]): Unit = {
    val r1 = new Rational(10, 15)
    val r2 = new Rational(9, 15)
    println("print "+r1)
    println("r1 + r2 = "+ (r1 + r2))
    // *は+よりも優先度が高い
    println("r1 + r2 * r2 = "+ (r1 + r2 * r2))
    println("r1 < r2 ? "+ (r1 lessThan r2))
    println("r2 < r1 ? "+ (r2 lessThan r1))

  }
}

Scalaの識別子

Scalaの識別子には、英数字識別子、演算子識別子、ミックス識別子、リテラル識別子の4つがあります。

英数字識別子

先頭が英字かアンダースコアで、その後に英字、数字、アンダースコアが続きます。$も英字に含まれますが$はScalaコンパイラのために予約されているので使わないでおきましょう。

演算子識別子

一つ以上の演算子文字からなる識別子です。たとえば+や:、?、~、#などです。一つ以上なので、:::や<?>、:->も有効な演算子識別子です。

ミックス識別子

ミックス識別子はその名の通り英数字識別子と演算子識別子両方を含む識別子です。たとえばunary_+は単項演算子+を定義するメソッドの名前として使用します。他にも、myvar_=は代入演算子を定義するメソッドの名前として使用します。

リテラル識別子

リテラル識別子はバッククオートで囲まれた任意の文字列を識別子とするものです。`x`, `<client>`, `yield`がそうです。

Scalaの定数

Javaでは定数はすべて大文字のアンダースコア区切りをします。たとえばMAX_VALUEなどです。Scalaでは先頭大文字のキャメルケースを使用します。たとえばMaxValueなどです。

暗黙の型変換

メソッドの多重定義により、r * 2のような演算は定義できましたが、2 * rは実行できません。Int型の2は、Rational型を取る*メソッドが無いからです。しかし、暗黙の型変換を定義することで実現できます。
scala> implicit def intToRational(x: Int) = new Rational(x)
を実行することで2 * rを実行することができます。
暗黙の型変換は21章でさらに解説があるようです。

No Comments

Post a Comment

コメントを投稿するには、下の計算の答えを入力する必要があります。答えは半角数字で入力してください。 * Time limit is exhausted. Please reload the CAPTCHA.