クラスの宣言、コンストラクタ
宣言とインスタンス化
シンプルなクラス宣言
/** class and instance sample */
class SimpleClass {
}
new でインスタンス化できる。
scala> val hoge = new SimpleClass
hoge: SimpleClass = SimpleClass@51ea07a3
基本コンストラクタ
デフォルトコンストラクタでの処理はクラス内に直接記載すればよい。
/** class and instance sample */
class SimpleClass {
// インスタンス化のタイミングで実行される。
println("create SimpleClass")
}
scala> val hoge = new SimpleClass
create SimpleClass
hoge: SimpleClass = SimpleClass@5db2381b
コンストラクタが引数をもつ場合は、宣言時にクラス名の後ろに引数を定義する。
/** class and instance sample */
class SimpleClass(id:String) {
// インスタンス化のタイミングで実行される。
println("create SimpleClass id:" + id)
}
scala> val hoge = new SimpleClass("test")
create SimpleClass id:test
hoge: SimpleClass = SimpleClass@40ab627a
基本コンストラクタが引数有りなので、引数なしではインスタンス化できない。
scala> val hoge = new SimpleClass
:7: error: not enough arguments for constructor SimpleClass: (id: String)SimpleClass.
Unspecified value parameter id.
val hoge = new SimpleClass
補助コンストラクタ
基本コンストラクタ以外のコンストラクタを定義する場合は、 sub this(...) で定義する。
補助コンストラクタは、必ず始めに基本コンストラクタを呼ばないといけない。
/** class and instance sample */
class SimpleClass(id:String) {
// インスタンス化のタイミングで実行される。
println("create SimpleClass id:" + id)
// 補助コンストラクタ
def this() {
// 先頭で基本コンストラクタを呼び出す必要がある。
this("dummy");
println("create by sub contracter")
}
}
scala> val piyo = new SimpleClass
create SimpleClass id:dummy
create by sub contracter
piyo: SimpleClass = SimpleClass@5babd8cb
メソッドの宣言
メソッド宣言の基本
def メソッド名(引数):戻り値 でメソッドを宣言する。ドット指定で呼び出せる。
/** method sample */
class SimpleClass2 {
def sayHello(name:String):Unit = {
println("hello, " + name + "!!");
}
}
scala> val hello = new SimpleClass2
hello: SimpleClass2 = SimpleClass2@75bc45de
scala> hello.sayHello("taro")
hello, taro!!
オーバーロード
引数の数、型を変えることで同名のメソッドを定義できる。
/** method sample */
class SimpleClass2 {
def sayHello(name:String):Unit = {
println("hello, " + name + "!!");
}
// 引数が異なればオーバーロード可能
def sayHello(times:Int):Unit = {
println("hello," * times);
}
def sayHello(name:String, times:Int):Unit = {
println(( "hello," * times ) + " " + name + "!!");
}
// 戻り値が異なるメソッドは定義できない。
/* 以下はコンパイルエラーになる。
def sayHello(times:Int):String = {
"hello" * times;
}
*/
}
scala> val hello = new SimpleClass2
hello: SimpleClass2 = SimpleClass2@2448b7f
scala> hello.sayHello("jiro")
hello, jiro!!
scala> hello.sayHello(3)
hello,hello,hello,
名前付き引数
引数名を指定して呼び出すことで、定義順を無視して引数を指定することができる。
scala> hello.sayHello("hoge",3)
hello,hello,hello, hoge!!
scala> hello.sayHello(times=3, name="hoge")
hello,hello,hello, hoge!!
引数のデフォルト値
/** method sample */
class SimpleClass2 {
def sayHello(name:String):Unit = {
println("hello, " + name + "!!");
}
// 引数が異なればオーバーロード可能
def sayHello(times:Int):Unit = {
println("hello," * times);
}
def sayHello(name:String, times:Int):Unit = {
println(( "hello," * times ) + " " + name + "!!");
}
// 戻り値が異なるメソッドは定義できない。
/* 以下はコンパイルエラーになる。
def sayHello(times:Int):String = {
"hello" * times;
}
*/
// 引数にデフォルト値を定義
def sayBye(name:String, times:Int = 3):Unit = {
println( ("Bye,"*times) + " " + name + "!!" );
}
}
引数にデフォルト値を定義することで、メソッド呼び出し時に引数を省略することができる。
scala> hello.sayBye("tanaka", 2)
Bye,Bye, tanaka!!
scala> hello.sayBye("tanaka")
Bye,Bye,Bye, tanaka!!
暗黙の引数
引数の型に implicit を書くと、暗黙の引数となる。
引数を省略した際に、呼び出し先のスコープにて implicit 付きで定義された変数が暗黙的に設定される。
/** method sample */
class SimpleClass2 {
def sayHello(name:String):Unit = {
println("hello, " + name + "!!");
}
// 引数が異なればオーバーロード可能
def sayHello(times:Int):Unit = {
println("hello," * times);
}
def sayHello(name:String, times:Int):Unit = {
println(( "hello," * times ) + " " + name + "!!");
}
// 戻り値が異なるメソッドは定義できない。
/* 以下はコンパイルエラーになる。
def sayHello(times:Int):String = {
"hello" * times;
}
*/
// 引数にデフォルト値を定義
def sayBye(name:String, times:Int = 3):Unit = {
println( ("Bye,"*times) + " " + name + "!!" );
}
// 暗黙の引数を定義
def greet(implicit name:String):Unit = {
println( "Hi! " + name );
}
}
scala> val hello = new SimpleClass2
hello: SimpleClass2 = SimpleClass2@4e1f52a
scala> implicit val name = "tanaka"
name: String = tanaka
scala> hello.greet
Hi! tanaka
scala> hello.greet("sato")
Hi! sato
変数が定義されていないとコンパイルエラーになる。
scala> val hello = new SimpleClass2
hello: SimpleClass2 = SimpleClass2@4e1f52a
scala> hello.greet
:9: error: could not find implicit value for parameter name: String
hello.greet
^
フィールドとアクセサ
フィールドの宣言
フィールドはクラス内に直接定義できる。
/** field sample */
class SimpleClass3 {
// 変更可能なフィールド
var var_id:Int = 1;
// 不変なフィールド
val val_id:Int = 2;
// 外部から参照できないフィールド
private val private_id = 999;
}
外部からはフィールド名指定での参照・設定が可能。
scala> val hoge = new SimpleClass3
hoge: SimpleClass3 = SimpleClass3@10f8ed
scala> hoge.var_id
res0: Int = 1
scala> hoge.var_id = 3
hoge.var_id: Int = 3
scala> hoge.var_id
res1: Int = 3
不変なフィールドは参照のみ可能。
scala> hoge.val_id = 3
:8: error: reassignment to val
hoge.val_id = 3
^
privateなフィールドは参照も不可。
scala> hoge.private_id
:9: error: value private_id in class SimpleClass3 cannot be accessed in SimpleClass3
hoge.private_id
^
アクセサ
フィールドへのアクセスは、暗黙的に生成されるアクセサを経由して行われている。
getterは変数名、setterは変数名_=(xxx)だが、変数名=xxxという形式でも呼び出せる。(こちらのほうが自然)
/** field sample */
class SimpleClass3 {
// 変更可能なフィールド
var id:Int = _; // _ は型のデフォルト値
}
scala> val hoge = new SimpleClass3
hoge: SimpleClass3 = SimpleClass3@6143c610
scala> hoge.id = 3
hoge.id: Int = 3
scala> hoge.id_=(999)
scala> hoge.id
res5: Int = 999
明示的にアクセサを定義する場合は、上記ルールに則ってメソッドを定義し、フィールドはprivateにしてアクセスを制約すればよい。
呼び出し元に変化がないところがポイント
/** field sample */
class SimpleClass3 {
// アクセサを独自実装するため、privateとする。
private var _id:Int = _; // _ は型のデフォルト値
// getter
def id:Int = {
println("call getter!");
_id;
}
// setter
def id_= (id:Int) = {
println("call setter!");
_id = id;
}
}
scala> val hoge = new SimpleClass3
hoge: SimpleClass3 = SimpleClass3@16becf68
scala> hoge.id = 3
call setter!
call getter!
hoge.id: Int = 3
scala> hoge.id_=(999)
call setter!
scala> hoge.id
call getter!
res1: Int = 999