S-JIS[2010-12-12/2017-01-18] 変更履歴
ScalaのAny・AnyVal・AnyRefクラス関連のメモ。
Javaの全てのクラスがObjectクラスから派生しているように、ScalaではAnyクラスから派生している。
Anyの直下(直接の子クラス)にはAnyRefとAnyValがある。
AnyValはIntやLong・Double等の値のクラスを表す。(Javaのプリミティブ型に相当)
AnyRefはそれ以外のクラスを表す。(Javaの参照型に相当)
nullはAnyRefの全てのクラス(の変数)に代入できる。
nullはNullというクラスの値になっており、Null型は全てのAnyRefの子クラスの下に位置づけられる。
(したがって、ScalaではInt等も含めて全ての型がオブジェクトということになっているけれども、Int等(のAnyValの派生クラス)の変数にはnullを代入できない)
AnyVal・AnyRefも含めて全てのクラスの子クラスとしてNothingが存在する。
Any | 最上位 | |
AnyVal | AnyRef |
↑ |
Unit Int Long Double 等 |
通常のクラス (Java・Scala) |
|
Null | ||
Nothing | 最下位 |
scala.Anyクラスは、Scalaの全ての親クラス。
メンバー | 説明 | 備考 |
---|---|---|
def ==(arg: Any) : Boolean |
オブジェクトの値(内容)が等しいかどうかを返す。 自分自身がnullの場合はargもnullのときtrue。[2017-01-18] null以外の場合はequals()メソッドを呼び出す。 したがって、nullと比較するときは「obj == null」でも良い。 |
→==とeqの違い |
def !=(arg: Any) : Boolean |
オブジェクトの値(内容)が等しくないかどうかを返す。 実体としては「 !(自分==arg) 」。 |
|
def ##() : Int |
ハッシュコードを返す。[2017-01-18] 「 null.## 」は0、それ以外はhashCode()と同じ。 |
|
def hashCode() : Int |
JavaのObject#hashCode()と同様。[2017-01-18]null.hashCode() はNullPointerExceptionになる。 |
|
def isInstanceOf[T] : Boolean |
クラスTの子クラスかどうか(Tにキャストできるかどうか)を返す。 | →使用例 |
def asInstanceOf[T] : T |
クラスTにキャストする。 |
ただしクラスとしての実体(ソースファイル)は無いっぽい。
scala.AnyRefクラスは、全ての参照型の親クラス。
実体としてはJavaのjava.lang.Objectに該当し、Objectクラスのメソッドを呼び出せる。
メンバー | 説明 |
---|---|
def ==(arg: AnyRef) : Boolean |
オブジェクトの値(内容)が等しいかどうかを返す。 自分自身がnullの場合はargもnullのときtrue。 null以外の場合はequals()メソッドを呼び出す。 したがって、nullと比較するときは「obj == null」でも良い。[2017-01-18] |
def !=(arg: AnyRef) : Boolean |
オブジェクトの値(内容)が等しくないかどうかを返す。 |
def eq(arg: AnyRef) : Boolean |
インスタンスが同一かどうかを返す。 Javaの「==」に相当。 |
def ne(arg: AnyRef) : Boolean |
インスタンスが同一でないかどうかを返す。 実体としては「 !(自分 eq arg) 」。 |
def getClass() : java.lang.Class |
オブジェクトのクラスを返す。 JavaのObject#getClass()と同様。 |
def ##() : Int |
ハッシュコードを返す。 「 null.## 」は0、それ以外はhashCode()と同じ。[/2017-01-18] |
def hashCode() : Int |
JavaのObject#hashCode()と同様。null.hashCode() はNullPointerExceptionになる。[2017-01-18] |
def synchronized[T](arg: T) : T |
排他制御を行う。[2011-02-26] Javaのsynchronizedに相当。 |
ScalaではJavaのプリミティブ型に当たる型は無く、全てクラスとなっている。[2010-10-23]
AnyValは、そのInt・Long・Double等のクラスの親クラス。UnitクラスもAnyValに含まれる。
(パッケージ)クラス | Java相当 | 説明 | 値(の範囲) | 初期値 | 例(リテラル) | |
---|---|---|---|---|---|---|
scala | Unit | void | 型無し | () | () |
|
scala | Boolean | boolean | 真偽値 | true, false | false |
true |
scala | Char | char | Unicode文字 | シングルクォーテーションで囲む | '\0' |
'a' |
scala | Byte | byte | 1バイト整数 | scala.Math.MIN_BYTE〜MAX_BYTE | 0 |
10.toByte |
scala | Short | short | 16bit整数 | scala.Math.MIN_SHORT〜MAX_SHORT | 0 |
10.toShort |
scala | Int | int | 32bit整数 | scala.Math.MIN_INT〜MAX_INT | 0 |
123 |
scala | Long | long | 64bit整数 | scala.Math.MIN_LONG〜MAX_LONG | 0 |
123L |
scala | Float | float | 32bit浮動小数 | scala.Math.MIN_FLOAT〜MAX_FLOAT | 0.0 |
123.0F |
scala | Double | double | 64bit浮動小数 | scala.Math.MIN_DOUBLE〜MAX_DOUBLE | 0.0 |
123.0D |
以下のクラスはAnyValでなくAnyRefだが、ついでに。 | ||||||
scala | Symbol | シンボル | 文字列の前にシングルクォーテーションを付ける | null |
'zzz |
|
scala.math | BigInt | BigInteger | 任意精度の整数 | null |
BigInt(10) |
|
scala.math | BigDecimal | BigDecimal | 任意精度の固定小数 | null |
BigDecimal(10) |
Javaと違い、BigInt・BigDecimalにも四則演算(+-*/)が定義されている。
→Scalaの演算子
Scala2.10でAnyValを継承した値クラスが定義できるようになった。[2013-06-08]
値クラスにすると、そのインスタンスを使う箇所において“内部で保持している値を直接使う”ようなコードに変換されるので、実行効率が良い。
(値として直接使えない箇所ではインスタンスとして扱われる)
参考: Eugene Yokotaさんの値クラスと汎用トレイト
//例 class MyString(val s: String) extends AnyVal { def isUpper() = s.forall(_.isUpper) }
値クラスを定義する際は、AnyValをextendsする。
そして基本コンストラクター(クラス名の直後の引数部分)にpublicでvalな引数を必ず1つ(のみ)指定する。
(複数の引数を指定するとコンパイルエラーになる)
クラスのボディー部にはdefしか定義できない。(valやvar、内部classやtrait・objectを定義できない)
汎用トレイト(Anyから派生し、defしか無く、初期化を一切行わないトレイト)をミックスインすることは出来る。
Unitクラスは、JavaやC言語のvoidと同様に使う。つまりメソッド・関数において戻り値(返り値)が無い場合に指定する。[2010-11-28]
Scala | Java |
---|---|
def メソッド() : Unit = { 〜 } def メソッド() { 〜 } |
void メソッド() { 〜 } |
ただしUnitは、実際には「値が無い」のではなく、唯一の値「()
」を持つ。
例えば「Byteは-128〜127の256種類の値を持つ」「Booleanはtrueとfalseの2種類の値を持つ」というのと同様に、Unitは()という1種類の値だけを持つ。
したがってUnitを返すメソッドというのは、常に「()
」しか返らないので、「戻り値に意味が無い」という事になる。
Unitは常に同じ値しか返さないので値に意味が無い(違いが無い)、したがって“使い方はvoidと同様”という事なのだろう。
ちなみに、「()
」は要素数が0個のタプル(空のタプル)らしい。
なお、実際に「値が無い」ということを表すNothingというクラスがある。
Scalaでは、メソッドの戻り値や変数の代入先の型に応じて値を変換してくれる。[2011-06-12]
「def メソッド(): Int = "a"
」は、"a"
(String)をIntに変換しようとするが出来なくてコンパイルエラーになる。
「def メソッド(): Unit = "a"
」だとコンパイルは通るので、"a"
(String)からUnitへ変換しているように見える。
しかしコンパイルされると戻り型はJavaのvoidになるので、戻り値は単純に捨てられる。Unitへ変換されるわけではない。
これを逆コンパイルして見てみた。
Scala | コンパイルされたJavaのイメージ | 備考 |
---|---|---|
class A { def メソッド() : Unit = { "a" } } |
public class A implements ScalaObject { public void メソッド() { String tmp = "a"; } } |
テンポラリーの変数に代入して終わり。 戻り型がvoidなので、値を返していない。 |
class A { val s: Unit = "a" } |
public class A implements ScalaObject { private final BoxedUnit s; public A() { String tmp = "a"; s = BoxedUnit.UNIT; } public void s() { } } |
Unitを表すクラス(BoxedUnit)はあるようだが、BoxedUnit.UNITという固定値が入れられている。 名前からすると、(String→Unitの暗黙変換ではなくて、)オートボクシングの扱いなのかな? Scalaではpublicなフィールドにはアクセスする為のメソッドが用意されるが、 sの値を返すメソッドの戻り型もvoidになっている。 このメソッドを呼び出す側も、s()の戻り値を使わず直接BoxedUnit.UNITを使っている。 |
val a = new A val t = a.s |
final A a = new A(); final BoxedUnit t = BoxedUnit.UNIT; |
UnitはJavaやC言語のvoidと同様の使い方をするが、実際には値が無いわけでは無い。[2010-11-28]
「値が無い」という意味では、Nothingというクラスがある。
こちらは本当に値が無くて、Nothingを返すよう宣言したメソッドでは、値を返す事が出来ない。
Nothing | Unit |
---|---|
scala> def f():Nothing = { println(1) } <console>:5: error: type mismatch; found : Unit required: Nothing def f():Nothing = { println(1) } ^ |
scala> def f():Unit = { println(1) } f: ()Unit scala> val v = f() 1 v: Unit = () |
例えばプログラムの実行を終了するexit()関数は、戻り型がNothingで定義されている。
(プログラムが終了してしまうので、呼び出し元に制御が戻ることが無い。つまり返す値が無い(値が返ることが無い))
scala> def f():Nothing = { exit(-1) } f: ()Nothing
あるいは、常に例外が発生するメソッドでは、戻り型をNothingにすることが出来る。
(使い道は…よく分からない^^;)
scala> def f():Nothing = { throw new Exception() } f: ()Nothing
余談だが、メソッドの戻り型を省略した際の型推論もちゃんと上記のようになる。
scala> def f() = exit(0) f: ()Nothing scala> def f() = throw new Exception() f: ()Nothing |
scala> def f() = println(1) f: ()Unit scala> def f() = {} //メソッド本体が空 f: ()Unit scala> def f() = () //Unitの値を指定 f: ()Unit |