Scalaの学習の第一歩として、Scalaにおける型の基礎と、変数の定義・型アノテーションについて学んでみました。
JavaScriptやRustのように、再代入可能な変数と再代入不可能な変数を明示的に分けて記述することができます。
Scalaの型階層構造
プログラミング言語では型は階層構造で示すことができます。
Scalaの場合は、下図のような階層構造をなしており、Anyという型をトップとして、文字列・数値などの型がそのサブタイプとして定義されています。
Any
Any型は、Scalaで扱うあらゆる型のスーパータイプとなる型で、トップ型とも呼ばれます。
あらゆる型のスーパータイプなので、あらゆる値を割り当てることができますが、静的型付けの利点を損なうリスクが大きいのであまり使わない方が得策。
var anyVal: Any = 123
println(anyVal) // 123
anyVal = "Test" // 数値の入っていた変数に文字列を代入可能
println(anyVal) // "Test"
AnyVal, AnyRef
AnyValはAnyの直下に位置するサブクラスです。
Javaでいうところのプリミティブ型相当の型ですが、Scalaにはプリミティブ型は存在せず、真偽値なども含めてすべてオブジェクトになっています。
また、AnyRefも同様にAnyの直下に位置しており、こちらは参照型を意味しています。
AnyVal以外の型やユーザー定義型はすべてAnyRefのサブタイプとなります。
var anyVal: AnyVal = 1.234
anyVal = ()
anyVal = false
anyVal = 'a'
// anyVal = "Hello" // 文字列の代入はエラー
// anyVal = List() // AnyValにAnyRefのサブタイプは代入できない
var anyRef: AnyRef = List()
anyRef = Some("Test")
anyRef = null
// anyRef = 123 // AnyRefにAnyValのサブタイプは代入できない
Nothing, Null
Nothingは上記のあらゆる型のサブタイプとなる型でボトム型と呼ばれます。
TypescriptでいうところのNever型ですね。
Nullはすべての参照型、つまりAnyRef型のサブタイプです。
JVM言語との相互運用のために用意されている型で、Scalaのコード内ではあまり使われるべきではないそう。
Javaのプリミティブ相当の型
object TypeAndAnnotations extends App {
val bool: Boolean = false
val str: String = "Hello"
val char: Char = 'a'
val byte: Byte = 127
val short: Short = 32767
val int: Int = 2147483647
val long: Long = 9223372036854775807L
val float: Float = 2.0f
val double: Double = 3.14
val unit: Unit = ()
val nl: Null = null
val lst: List[String] = List("Hello", "Scala")
val opt: Option[String] = Some("Some")
}
型名 | 概要 | 例 |
Boolean | 真偽値 | true, false |
String | 文字列 ダブルクォーテーション(””)で囲う | “Hello World” |
Char | 16ビット符号なしUnicode文字 シングルクォーテーション(”)で囲う | ‘a’ |
Byte | 8ビット符号付き整数 | 127, -128 |
Short | 16ビット符号付き整数 | 32767, -32768 |
Int | 32ビット符号付き整数 | 2147483647, -2147483648 |
Long | 64ビット符号付き整数 | 9223372036854775807L |
Float | 32ビット浮動小数点数 | 2.0f |
Double | 64ビット浮動小数点数 | 3.14 |
変数定義とアノテーション
すでにコードに記載していますが、Scalaでは変数定義にvalとvarキーワードを用います。
それぞれの役割は以下のような感じ。
- val : 再代入を許可しない変数の定義。Scalaのコードにおいてはなるべくこちらを使った方がよい
- var : 再代入可能な変数の定義。
変数定義時の型アノテーション
基本的には、コンパイラーがコンパイル時に型を推論してくれるため、明示的に型アノテーションをつける必要はない場合が多い。
val str: String = "Hello Annotation"
val str = "Hello Annotation" // 型アノテーションなしでもString型に推論してくれる
val strList = List("This", "is", "a", "list") // List[String]型に推論してくれる
まとめ
- Scalaの型はAny型をトップ、Nothing型をボトムとした階層構造になっている
- Scalaではあらゆる型がオブジェクトでJavaのプリミティブ相当の型はない
- コンパイラが賢いので型のアノテーションは不要なことが多い
今回はScala学習の第一歩ということで軽めの内容でした。
次回は、条件分岐やループなどの制御構文を取り上下ていきたいと思います。
コメント