ってことで始めます
twitterで流します
class Greeter {
// クラスの中味
}
// Greeter : 挨拶する人
val yamada = new Greeter();
val ueda = new Greeter();
クラスの初期化を行いたいときに使います
class Greeter {
// ここに書いた処理がそのままコンストラクタの処理になる
println("**********");
println("Created !");
println("**********");
}
class Greeter(name: String) {
def myName() = name
}
yamada = new Greeter("yamada")
yamada.myName()
// yamada
class Greeter(name: String) {
// 公開メソッド
def sayHello(name: String): Unit = {
println( mkHello(name) )
println( "My name is " + myName() )
}
// 非公開メソッド
private def mkHello(name: String): String = {
s"Hello! ${name}"
}
}
class Greeter(name: String){
val myName = name
}
冗長なので以下のように書ける
class Greeter(val name: String)
シングルトンなものを表します.
例えばアプリケーションそのものは一つしか無いものです。
object SayHello {
def say() = println("Hello")
}
SayHello.say()
// Hello
次からはハンズオンな感じで
これ以降は複素数を表すComplexクラスを用いて説明をします.
エディタを使って以下のコードをComplex.scalaという名前で保存して下さい(コピペ可)
// real : 実部
// imaginary : 虚部
class Complex(real: Double, imaginary: Double) {
def r() = real
def i() = imaginary
}
※sample/Complex1.scalaがソレです
続いて以下のコードを同じComplex.scalaの下に追加.
object ComplexNumbers {
def main(args: Array[String]) {
val c = new Complex(1.2, 3.4)
println("real part : " + c.r())
println("imaginary part: " + c.i())
}
}
書けたらComplex.scalaの在るディレクトリで以下のコマンドを実行.
scalac Complex.scala
scala ComplexNumbers
// real part : 1.2
// imaginary part: 3.4
実行できましたか?
先ほどのコードのこの部分
println("real part : " + c.r())
println("imaginary part: " + c.i())
この部分
c.r()
c.i()
メソッド(関数)をフィールド(変数)の様に呼び出せれば、4回タイピング回数が減らせる.
先ほどのComplexクラスを以下のように変更
class Complex(real: Double, imaginary: Double) {
def r = real
def i = imaginary
}
class Complex(real: Double, imaginary: Double) {
- def r() = real
- def i() = imaginary
+ def r = real
+ def i = imaginary
}
※sample/Complex2.scalaがソレです
ComplexNumbersも以下のように変更
object ComplexNumbers {
def main(args: Array[String]) {
val c = new Complex(1.2, 3.4)
println("real part : " + c.r)
println("imaginary part: " + c.i)
}
}
- println("real part : " + c.r())
- println("imaginary part: " + c.i())
+ println("real part : " + c.r)
+ println("imaginary part: " + c.i)
}
書けたらComplex.scalaの在るディレクトリで以下のコマンドを実行.
scalac Complex.scala
scala ComplexNumbers
// real part : 1.2
// imaginary part: 3.4
実行できましたか?
引数の無いメソッドは括弧を省略できる.
object ComplexNumbers {
def main(args: Array[String]) {
val c = new Complex(1.2, 3.4)
println("real part : " + c.r)
println("imaginary part: " + c.i)
}
}
println("real part : " + c.r)
println("imaginary part: " + c.i)
いちいち文字列構築するの面倒くさい
インスタンスの内容をいちいち文字列を構築して表示するのは面倒なので、toStringに任せたい.
しかし…
val c = new Complex(1.2, 3.4)
println(c.toString)
を実行すると以下の様な結果になる.
Complex@625dcec6
スーパークラスを指定していない場合、Scalaではscala.Objectというクラスが勝手にスーパークラスになる.
scala.ObjectのtoString()はクラス名@ハッシュで人間に分かり難い文字列が返ってくるので、適切にoverrideしよう!
Complexクラスを以下のように変更
class Complex(real: Double, imaginary: Double) {
def r = real
def i = imaginary
// r± ai 的な感じで表示する.
override def toString() = f"$r%f$i%+fi"
}
+ // r ± ai 的な感じで表示する.
+ override def toString() = f"$r%f$i%+fi"
※ぶっちゃけ魔術
ComplexNumbersも以下のように変更
object ComplexNumbers {
def main(args: Array[String]) {
val c = new Complex(1.2, 3.4)
println(c.toString)
}
}
- println("real part : " + c.r)
- println("imaginary part: " + c.i)
+ println(c.toString)
書けたらComplex.scalaの在るディレクトリで以下のコマンドを実行.
scalac Complex.scala
scala ComplexNumbers
// 1.200000+3.400000i
実行できましたか?
スーパークラスのメソッドのオーバーライドにはoverrideキーワードが必ず必要
不用意なオーバーライドを避けるためです.
new Complex(1.2, 3.4)
new Complex(1.2, -3.4)
class Complex(real: Double, imaginary: Double) {
def r = real //ここと
def i = imaginary //ここ
}
その前に以下のことを解説します
クラス定義と同一のファイルに同一の名前で定義したobject
// コンパニオンクラス
class Complex(real: Double, imaginary: Double) {
def r = real
def i = imaginary
override def toString() = f"$r%f$i%+fi"
}
// コンパニオンオブジェクト
object Complex {
}
言葉で説明するよりコードで!
applyは特別なメソッドで以下のように書くと
object Complex {
def apply(i: Double, r: Double) = {
println(f"$r%f$i%+fi")
}
}
Complex.apply(1.2, 3.4)
の変わりに
Complex(1.2, 3.4)
と書ける!!
前回やった
val list = List(1, 2, 3, 4)
とかも実は
val list = List.apply(1, 2, 3, 4)
を呼び出しているのです.
コンパニオンオブジェクト & applyメソッドは原則としてインスタンスを生成するためのファクトリメソッドとして使用します
// コンパニオンクラス
class Complex(real: Double, imaginary: Double) {
def r = real
def i = imaginary
override def toString() = f"$r%f$i%+fi"
}
// コンパニオンオブジェクト
object Complex {
def apply(i: Double, r: Double) = {
new Complex(i, r)
}
}
// val c = Complex(1.2, 3.4)と書ける
コンパニオンオブジェクトでファクトリメソッドを作れば、インスタンス化時にnewが要らなくなる.
val c = new Complex(1.2, 3.4)
が
val c = Complex(1.2, 3.4)
と書ける
今度こそケースクラスです
ケースクラスとは以下の機能がモリモリなクラスのことだ!!
class Complex(real: Double, imaginary: Double) {
def r = real
def i = imaginary
}
object Complex {
def apply(i: Double, r: Double) = { new Complex(i, r) }
}
case class Complex(r: Double, i: Double)
_人人人人人人人_ > 突然の1行 <  ̄Y^Y^Y^Y^Y^Y ̄
scala> case class Complex(r: Double, i: Double)
defined class Complex
scala> val c = Complex(1.2, 3.4)
c: Complex = Complex(1.2,3.4)
scala> c.r
res0: Double = 1.2
scala> c.i
res1: Double = 3.4
scala> c.toString
res2: String = Complex(1.2,3.4)
toStringは自動生成されますが、
c.toString
// Complex(1.2, 3.4)
という感じ(コンストラクタっぽく)に生成されますので、気に喰わない場合は以下のようにoverrideしてください
case class Complex(r: Double, i: Double) {
override def toString() = f"$r%f$i%+fi"
}
ということで