Scalaでの型宣言
1. 序章
Scala は、静的に型付けされたプログラミング言語です。 これは、コンパイラがコンパイル時に変数のタイプを決定することを意味します。
型宣言は、独自の型を宣言できるScala機能です。
この短いチュートリアルでは、typeキーワードを使用してScalaで型宣言を行う方法を学習します。 まず、タイプエイリアスとして使用する方法を学びます。 次に、抽象型メンバーを宣言して実装する方法を学びます。
2. タイプエイリアス
タイプエイリアスは通常、パラメータ化されたタイプや関数タイプなどの複雑なタイプの宣言を簡素化するために使用されます。
それらのエイリアスの例を調べて、タイプエイリアスのいくつかの違法な実装も見てみましょう。
2.1. パラメータ化されたタイプのタイプエイリアス
整数のリストのショートカットを定義しましょう。
object ListIntFunctions {
type IntItems = List[Int]
}
ここでは、IntItemsをList[Int]の型エイリアスとして定義しました。 このようにして、 List[Int]の代わりにIntItemsを使用して、もう少し読みやすくし、それを実装する方法の中心的な定義を提供できます。
オブジェクト内のメソッドでIntItemsを使用してみましょう。
def mean(items: IntItems): Double = {
items.sum.toDouble / items.length
}
itemsでsumとlength – List のメソッド–を使用できることがわかります。
ListIntFunctionsオブジェクトの外部でmeanを使用する場合は、パラメーターに List[Int]を使用することもできます。
val intList = List(3, 6, 2, 2)
assert(ListIntFunctions.mean(intList) === 3.25)
List [int] を定義すると、別の型エイリアスを使用することもできます。
type SomeInts = List[Int]
val intList: SomeInts = List(3, 6, 2, 2)
assert(ListIntFunctions.mean(intList) === 3.25)
つまり、 List[Int]またはそのエイリアスを同じ意味で使用できます。
2.2. 関数タイプのタイプエイリアス
タイプエイリアスのもう1つのユースケースは、関数タイプです。 型エイリアスを使用して、関数型の宣言を簡略化し、後で他のメソッドで使用することができます。
たとえば、 Int パラメータを持ち、Stringを返す任意の関数の型エイリアスを作成できます。
type IntToString = Int => String
次に、メソッドでタイプエイリアスを使用できます。
def IntItemsToString(items: IntItems, intToString: IntToString): List[String] = {
items.map(intToString)
}
これを使用するには、まず、IntItemsとIntToStringを宣言して、後でメソッドで使用します。
val intList = (1 to 3).toList
def getChicken(item: Int): String = {
s"$item chicken"
}
次に、IntItemsToStringをintListおよびgetChickenで適用できます。
val stringList = ListIntFunctions.IntItemsToString(intList, getChicken)
assert(stringList === List("1 chicken", "2 chicken", "3 chicken"))
ご覧のとおり、 intList のすべてのメンバーは、getChicken関数によってニワトリになります。
2.3. 不正なタイプエイリアス
タイプエイリアスを宣言するときに避ける必要がある場合があります。
まず、それ自体への参照を使用して型エイリアスを作成することは違法です。
scala> type A = List[A]
<console>:11: error: illegal cyclic reference involving type A
次に、パラメータを定義せずに、必要なパラメータを持つ型の型エイリアスを作成することはできません。
scala> type T = List
<console>:11: error: type List takes type parameters
最後に、 Tuple のように、複数の要素を持つ別のタイプの部分を選択することはできません。
scala> type Y = Tuple2[Int, String]
defined type alias Y
scala> type Z = List[Y.key]
<console>:11: error: not found: value Y
3. タイプメンバー
タイプメンバーは、スコープ内で使用されるオブジェクト、クラス、またはトレイトで宣言できます。 最も一般的なアプリケーションは、抽象型メンバーです。これは、トレイトで宣言し、実装クラスの任意の型に割り当てることができます。
3.1. 抽象型メンバー
例として、値またはアイテムに対して繰り返しを実行するオブジェクトを作成する必要があるとします。 これらのオブジェクトはトレイトから実装されるため、すべて同じコントラクトを持ちます。
この目的のためにRepeatトレイトを作成しましょう。
trait Repeat {
type RepeatType
def apply(item: RepeatType, reps: Int): RepeatType
}
RepeatType を、Repeatを拡張するクラスで定義する必要があるタイプとして定義しました。 また、割り当てるタイプに応じて、applyメソッドを実装する必要があります。
それでは、抽象型メンバーを実装する方法を見てみましょう。
3.2. 抽象型メンバーの実装
トレイトを実装するクラスに抽象型を実装できます。 IntタイプのRepeatトレイトを実装しましょう。
object IntegerRepeat extends Repeat {
type RepeatType = Int
def apply(item: RepeatType, reps: Int): RepeatType = {
(item.toString * reps).toInt
}
}
それでは、IntegerRepeatの機能を見てみましょう。
assert(IntegerRepeat(3, 5) == 33333)
assert(IntegerRepeat(10, 3) == 101010)
ご覧のとおり、 item を繰り返す回数として、repsパラメーターを使用して新しい整数を作成します。
Listを繰り返す別のオブジェクトを実装しましょう。
object ListRepeat extends Repeat {
type RepeatType = List[Any]
def apply(item: RepeatType, reps: Int): RepeatType = {
(1 to reps).map(_ => item).reduce(_ ::: _)
}
}
ListRepeatはIntegerRepeatと同じ特性を拡張しますが、まったく異なる種類の操作を実行します。
ListRepeatがListで何をするか見てみましょう。
assert(ListRepeat(List("a", "b"), 2) == Seq("a", "b", "a", "b"))
assert(ListRepeat(List(1), 3) == Seq(1, 1, 1))
4. 結論
この記事では、Scalaのtypeキーワードについて説明しました。
複雑な型と関数型を単純化するための型エイリアスを作成する方法を見てきました。 次に、抽象型メンバーを作成して実装する方法を説明しました。
いつものように、この記事のサンプルコードは、GitHubでから入手できます。