変数と型¶
変数宣言¶
val は不変、var は可変です。型は推論されますが、明示もできます。
型システム¶
プリミティブ型¶
先頭が大文字です:Int / Long / Double / Float / Boolean / Byte / Short / Char。
val i: Int = 42
val l: Long = 100L // L 接尾辞
val d: Double = 3.14
val f: Float = 2.5f // f/F 接尾辞(d/D も可)
Double / Int などはプリミティブとして直接書け、Object / Number のスロットへは自動的にボクシングされます(ラッパークラスは JDouble / JInteger …)。
参照型・配列型¶
String、クラス型、インターフェース型、配列。
val s: String = "hello"
val arr: Int[] = new Int[5]
arr[0] = 10
val len = arr.length // length はメソッドではなくプロパティ
Nullable型¶
T? で null を許可します。詳細は Null安全 を参照してください。
型キャスト¶
as 演算子を使います。メソッドチェーンには括弧が必要です。
- 拡大変換(
Int→Long→Double)は自動です - 縮小変換は明示的な
asが必要です
変数スコープ¶
ローカル変数、フィールド、static 変数があります。トップレベルの val はスクリプトの合成クラスのフィールドに昇格されつつ、if x != null のスマートキャストも効きます。
ジェネリック型¶
ジェネリック型は [] で型引数を指定します(raw 型は禁止 = E0066)。型引数にはプリミティブ型(Int など)も使え、JVM の消去に伴い境界で自動的にボックス化/アンボックス化されます:
型引数の不変性¶
型引数は不変です。Dog が Animal の派生型であっても、Box[Dog] は Box[Animal] に代入できません(ヒープ汚染を防ぐため)。互換なのは同一のパラメータ化だけです:
class Animal { public: def this {} }
class Dog : Animal { public: def this {} }
class Box[T] {
val v: T
public:
def this(x: T) { v = x }
def get(): T = v
}
val bd: Box[Dog] = new Box(new Dog())
val same: Box[Dog] = bd // OK: 同一のパラメータ化
// val wide: Box[Animal] = bd // エラー E0000: Box[Dog] は Box[Animal] ではない
不変性は型引数に適用されるもので、ジェネリッククラス自体は通常の派生関係に従います(例: ArrayList[String] は List[String])。