1. 序章

このチュートリアルでは、Scalaのさまざまなデータ型について説明します。 これらのタイプがデータにどのように関連付けられているか、それらに対して実行できる操作、およびJavaとの相互運用性について見ていきます。

2. 一般的なタイプ

2.1. 値型

他のプログラミング言語と同様に、Scalaは数値型を提供します。 そのようなタイプは7つあります。

  • Char (16ビット符号なしUnicode文字)
  • バイト(8ビット符号付き値)
  • Short (16ビット符号付き値)
  • Int (32ビット符号付き値)
  • Long (64ビット符号付き値)
  • Float (32ビットIEEE 754単精度浮動小数点値)
  • Double (64ビットIEEE 754単精度浮動小数点値)

これらに加えて、さらに2つの値型があります。

  • ブールtrueまたはfalseの値を持つことができます)
  • ユニット(意味のある情報はありません)

それぞれにJavaの対応物があります。 違いは、それらが表現される方法にあります。 Scalaでは、これらの型はプリミティブ型をラップアラウンドし、それらに対する操作はすべて関数呼び出しです。

次のセクションでは、これらの各タイプを例とともに見ていきます。

2.2. バイトおよび文字

Byte は、-128〜127の範囲の値を保持できる符号付き8ビット値です。 Char は16ビット値であり、人間が読める文字を格納するために使用されます。

いくつかのByteおよびChar変数を見てみましょう。

val b1: Byte = 100
val c1: Char = 'A'
// val b3: Byte = 169 (will not compile)

Byte は、符号付き8ビット値を保持できます。 値169はその範囲を超えているため、コンパイラーは文句を言います。 Char に169を割り当てると、ASCII著作権文字として解釈されます。

b1 should be(100) 
c1 should be('A')

2.3. 整数ロングおよびショート

Integer は32ビット値であり、Scalaの数値表現の中心です。 LongおよびShortタイプは、Integerに似ています。

それらがどのように使用されるかの例を見てみましょう:

val l1: Long = 65536 
val i3: Int = 32768 
val s1: Short = 32767 
// val s2: Short = 32768 (will not compile)

Shortが保持できる範囲を超える値を割り当てることはできないことがわかります。

2.4. ブール値

ブール値が最も単純です。 当然のことながら、ブールタイプの変数に2つの値のいずれかを割り当てることができます。

val trueVal = true 
val falseVal = !true 
val falseValOtherWay = !true 

trueVal should be (true) 
falseVal should be (false)

2.5. フロートおよびダブル

FloatおよびDoubleタイプは、精度に関連付けられた実数を保持するために使用されます。

val f1 = 12.05f // 'f' signifies that it is a Float 
val d1 = 12.3495067 // inferred as a Double 
val d2 = 12.3495067D // 'D' signfies a Double, but is optional

タイプDoubleの変数の最後に「D」を配置することはオプションですが、Floatの最後に「f」を配置することは必須です。

2.6. リテラルと型推論

Scalaは、変数を宣言するときに変数の型を常に提供することを義務付けていません。 Scalaコンパイラーは、初期化されているものに基づいて型を推測しようとします。

ここでリテラルが機能します。 リテラルと推測される型を定義するいくつかの例を見てみましょう。

// Types are inferred from the values assigned
val i5 = 1234 // inferred as an Int
val i6 = 0xAFBF // HEX value, inferred as an Int
val c5 = 234 // inferred as an Int
val c6 ='®' // inferred as a Char
val l4 = 1234L // 'L' signifies a Long literal
val l3 = 0xCAFEBABEL // 'L' signifies a Long literal, even for a HEX value
val trueVal = true // inferred as a Boolean
val falseVal = !true // inferred as a Boolean

タイプの整数リテラル Int長いです 10進数と16進数の2つの形式があります。 Charタイプを表すリテラルは一重引用符で囲まれています。 これらのタイプは、一重引用符のペア内の任意のUnicode文字にすることができます。

ただし、ByteおよびShortの場合、リテラルは十分ではありません。 これは、ShortまたはByteが保持できる値が、Intが保持できる値のサブセットを形成するためです。 したがって、次のタイプを指定する必要があります。

// Types are inferred from the values assigned
val s2: Short = 32767 // qualify with intended type
val b1: Byte = 127 // qualify with intended type

2.7. 文字列

リテラルがScalaにもたらすものを確認したので、StringがScalaでどのように初期化されるかを確認できます。

val name = "Diego Armando Maradona" 
val nameWithQuote = "Kerry O\'keffey" 
val ageAsString = "100"

文字列は二重引用符のペアで囲まれています。 バックスラッシュ( \ )は、上記の例の単一引用符のように、値内の特殊文字を保持するために使用されます。

3. タイプ間の変換

3.1. Intとの間の変換

Scalaを使用すると、他のデータ型からIntおよび 逆に。 もちろん、いくつかのルールに従う必要があります。

// val justAByte: Byte = 129  // Beyond the range of values allowed for Byte, will not compile

val aByteSizedInteger = 127
val byteFromInt = aByteSizedInteger.toByte
val aNonByteInteger = 128
val wrappedByte = aNonByteInteger.toByte // wrapped around
byteFromInt should be (127)
wrappedByte should be (-128)

Scalaでは、バイトに保持できる制限を超える値を直接割り当てることはできません。 ただし、変換機能を使用する toByte() Int では、はるかに予測可能で論理的な結果が得られます。

Scalaは、割り当てられた値をラップアラウンドします。 このラップアラウンドされた値は、Intにも簡単に戻すことができます。

3.2. CharまたはStringからIntへの変換

CharまたはStringIntに変換できます。

val c4: Char = '®'
val symbolToInt = c4.toInt // from a Char 
val stringToInt = "100".toInt

String に数字以外の文字が含まれている場合はどうなりますか? それをIntに変換できますか? 予想通り、私たちはいたずらで捕まります:

val i = "ABC".toInt
java.lang.NumberFormatException: For input string: "ABC"
  at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
  at java.base/java.lang.Integer.parseInt(Integer.java:652)
  at java.base/java.lang.Integer.parseInt(Integer.java:770)
  at scala.collection.immutable.StringLike.toInt(StringLike.scala:304)
  at scala.collection.immutable.StringLike.toInt$(StringLike.scala:304)
  at scala.collection.immutable.StringOps.toInt(StringOps.scala:33)
  ... 28 elided

3.3. Longs特別な言及が必要

Long が保持できる値は、本質的に Integers ですが、はるかに広い範囲の値を保持できます。 LongからIntへの変換、およびその逆の変換は、いくつかの制約の下で機能します。

val l = 65536L // Long literal
val i1 = 65536 // No qualifier, therefore Int
val i2 = l // i2 is a Long because RHS is a Long
// The following line will not compile because Long, a larger size is being cast into Into, a smaller size
// val i2: Int = l // the target variable's type is explicit: an Int
val i3 = l.toInt // Conversion helper function works
val s3 = l.toShort
l should be (65536L)
i1 should be (65536)
i2 should equal(i1.toLong)
i3 should equal(i1)
s3 should be (0) // Oops! A Short is too small for a large value as 65536

IntLongに割り当てることは、Longが保持できる値の範囲がIntの値の範囲よりもはるかに大きいため、安全です。 ただし、その逆は安全ではありません。 これは、割り当て中に値の精度が低下する可能性があるためです。 そのため、コンパイラはサイレント割り当てを拒否し、代わりに型の不一致を示します。

ただし、何をしているのかがわかっている場合は、正しいを使用できます。入力し()関数 Short は65536の値を保持できないため、 toShort ()関数はそれをゼロに減らし、割り当てによって値が縮小されることを示します。

3.4. 間違った変換からの保護

Scalaは型変換を管理する特定のルールを課しているため、値が型に割り当て可能かどうかを事前に知る必要があるかもしれません。 これを行うために、これらのタイプで役立つ関数を使用できます。

val i10 = 127 // Integer 127 
val i11 = 128 // Integer 128 
i11.isValidByte should be (false) 
i10.isValidByte should be (true) 
val i31 = 65536 
i31.isValidShort should be (false) 
val d3 = 2E31 
d3.isValidInt should be (false)

タイプのヘルパー関数 isValid {type-name}() 変数のがそのタイプが保持できる範囲内にあることを確認するのに役立ちます。

4. 値と参照:タイプ階層

Scalaは、明確に定義された型の階層に従います。 String 以外の上記の基本的なデータ型は、本質的にすべてValuesです。 当然のことながら、これらはまた呼ばれます バリュークラス。 これらのValueクラスは、という名前のScalaによって提供されるタイプを継承します。AnyVal.

一方、 String および私たちが作成する他のクラス(一般に ユーザー定義の クラス)ソリューションの実装中に、 AnyRef:という名前のScalaが提供する別のタイプから継承します

class Article(heading: String, noOfLines: Int)
val i: Int = 1234
val a1: AnyVal = i // casting an Int to AnyVal
val article = new Article("Baeldung",2000) // an application class
val author = "Eugene"
val parentClass1: AnyRef = article       // casting an User-Defined Object to an AnyRef
val parentClass2: AnyRef = author        // casting a String to an AnyRef

Scalaで使用するすべてのクラスは、いずれかのサブクラスです AnyVal また AnyRef.

5. タイプは残っていますか?

どれでも それは すべてのタイプの親つまり、 どれでも すべてのタイプのスーパータイプであり、トップタイプとも呼ばれます。

それは次のような特定の普遍的な方法を定義します equals(), ハッシュコード()、 と toString()。 の2つの直接サブクラス どれでも それは AnyValAnyRef

6. 結論

この記事では、Scalaのさまざまなデータ型について説明しました。 Scalaコンパイラが割り当てをどのように管理するかを観察しました。 さらに、Scalaコンパイラーが設計に課すクラスの階層に注目しました。 どれでも すべてのタイプのルートです。

この記事に関連するコードは、GitHubにあります。