■ はじめに
Scala で 色々なデータ型をサポートしたMapを作りたいと思い 調べていたら、以下が見つかったので、まとめておく。
https://stackoverflow.com/questions/43495047/scala-variable-with-multiple-types
目次
【1】用語整理 1)代数的データ型 (ADT; Algebraic Data Types) 2)一般化された代数的データ型 (GADT; Generalized Algebraic Datatype) 【2】使用するScala文法 1)sealed 2)trait (トレイト) 【3】サンプル 例1:様々データ型に対応したMap
【1】用語整理
https://stackoverflow.com/questions/43495047/scala-variable-with-multiple-types
で、ADT って何?っと思って調べてみた。(IMOも分からんけど) ~~~ IMO the most natural way to express this is to create an ADT (Algebraic Data Type): ~~~ * Scala の公式ドキュメントにも記載あり。
https://docs.scala-lang.org/scala3/book/types-adts-gadts.html
1)代数的データ型 (ADT; Algebraic Data Types)
* 主に関数型プログラミングでよく用いられる データ型を組み合わせることによって作られる型 cf. Algebraic([US]アルジャブレイイク、[UK]アルジブレイイク) = [形]代数の,代数による,代数学の(略alg.) => 日本語の詳細の解説は、以下のサイトなどを参照
https://zenn.dev/moony/articles/3c3e7fb49582e1
例:ADT
enum Color(val rgb: Int): case Red extends Color(0xFF0000) case Green extends Color(0x00FF00) case Blue extends Color(0x0000FF) case Mix(mix: Int) extends Color(mix)
2)一般化された代数的データ型 (GADT; Generalized Algebraic Datatype)
* 代数的データ型をより拡張性の高いもの => 以下の例とADTの例を見比べると分かるかも。。。
例:GADT
enum Box[T](contents: T): case IntBox(n: Int) extends Box[Int](n) case BoolBox(b: Boolean) extends Box[Boolean](b)
【2】使用するScala文法
1)sealed
* 同一ファイル内からのみ継承可能なクラス/トレイとのこと。 * sealedクラス = 封印されたクラス cf. ealed(シールド) = 密封された、封印された * C# の sealed とほぼ同じ感じ。
sealed キーワード ~ 継承禁止 / パフォーマンス向上 ~
https://dk521123.hatenablog.com/entry/2012/09/25/010153
2)trait (トレイト)
* 以下の関連記事を参照のこと
Scala ~ 基本編 / トレイト ~
https://dk521123.hatenablog.com/entry/2023/09/10/204016
【3】サンプル
例1:様々データ型に対応したMap
import ConfigType._ sealed trait ConfigType object ConfigType { final case class ConfigString(str: String) extends ConfigType final case class ConfigInt(int: Int) extends ConfigType final case class ConfigBoolean(bool: Boolean) extends ConfigType final case class ConfigStrings(list: List[String]) extends ConfigType } // 使用例 object Hello { def main(args: Array[String]): Unit = { val mapper: Map[String, ConfigType] = Map( "key1" -> ConfigString("value1"), "key2" -> ConfigInt(2), "key3" -> ConfigBoolean(true), "key4" -> ConfigStrings(List("value4_1", "value4_2", "value4_3")) ) mapper.foreach({ x => val key = x._1 val value = x._2 value match { // String -> key1 = value1 case ConfigString(str) => println(s"${key} = ${str}") // Int -> key2 = 2 case ConfigInt(int) => println(s"${key} = ${int}") // Boolean -> key3 = true case ConfigBoolean(bool) => println(s"${key} = ${bool}") // List[String] -> key4 = value4_1,value4_2,value4_3 case ConfigStrings(list) => println(s"${key} = ${list.mkString(",")}") } }) } }
例2:例1+拡張メソッド追加
import ConfigType._ sealed trait ConfigType object ConfigType { final case class ConfigString(str: String) extends ConfigType final case class ConfigInt(int: Int) extends ConfigType final case class ConfigBoolean(bool: Boolean) extends ConfigType final case class ConfigStrings(list: List[String]) extends ConfigType def toConfigType[T](value: T): ConfigType = { value match { case intValue: Int => ConfigInt(intValue) case boolValue: Boolean => ConfigBoolean(boolValue) case stringValue: String => ConfigString(stringValue) case listValues: List[String] => ConfigStrings(listValues) case _ => throw new IllegalArgumentException("No supported") } } def toPrintStr(value: ConfigType): String = { value match { case intValue: ConfigInt => s"Int - ${intValue.int}" case boolValue: ConfigBoolean => s"Boolean - ${boolValue.bool}" case stringValue: ConfigString => s"String - ${stringValue.str}" case listValues: ConfigStrings => s"List - ${listValues.list.mkString(",")}" case _ => "No supported" } } } object Hello { def main(args: Array[String]): Unit = { val mapper: Map[String, ConfigType] = Map( // ★ "key1" -> toConfigType("Hello"), "key2" -> toConfigType(2), "key3" -> toConfigType(true), "key4" -> toConfigType(List("value4_1", "value4_2", "value4_3")) ) mapper.foreach { case (key: String, value: ConfigType) => println(s"${key} - ${toPrintStr(value)}") } } }
出力結果例
key1 - String - Hello key2 - Int - 2 key3 - Boolean - true key4 - List - value4_1,value4_2,value4_3
それ以外のサンプル
* 以下の関連記事を参照のこと
Scala ~ implicit ~
https://dk521123.hatenablog.com/entry/2024/07/24/120726
Scala ~ asInstanceOf / isInstanceOf ~
https://dk521123.hatenablog.com/entry/2024/07/26/225713
関連記事
Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331
Scala ~ 基本編 / コレクション ~
https://dk521123.hatenablog.com/entry/2023/03/13/000345
Scala ~ コレクションで使えるメソッド ~
https://dk521123.hatenablog.com/entry/2023/09/07/223422
Scala ~ 基本編 / メソッド ~
https://dk521123.hatenablog.com/entry/2023/03/03/000000
Scala ~ 基本編 / 繰り返し ~
https://dk521123.hatenablog.com/entry/2023/01/24/000000
Scala ~ 基本編 / トレイト ~
https://dk521123.hatenablog.com/entry/2023/09/10/204016
Scala ~ 基本編 / パターンマッチング ~
https://dk521123.hatenablog.com/entry/2023/06/06/233614
Scala ~ Enum ~
https://dk521123.hatenablog.com/entry/2023/01/05/000000
Scala ~ implicit ~
https://dk521123.hatenablog.com/entry/2024/07/24/120726
Scala ~ asInstanceOf / isInstanceOf ~
https://dk521123.hatenablog.com/entry/2024/07/26/225713