【Scala】Scala ~ asInstanceOf / isInstanceOf ~

■ はじめに

今更だが、Scala の asInstanceOf / isInstanceOf を扱う。

目次

【1】asInstanceOf
 1)使用上の注意
【2】isInstanceOf
【3】サンプル
 例1:implicit Class の メソッド

【1】asInstanceOf

* Scala の キャスト

1)使用上の注意

* 例えば、「"false".asInstanceOf[Boolean]」とすると例外がでる

例:文字列 to 真偽 / 文字列 to 数字 での例外

object Hello {
  def main(args: Array[String]): Unit = {
    val target1 = "false"
    // ! Error !
    // java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Boolean
    //  (java.lang.String and java.lang.Boolean are in module java.base of loader 'bootstrap')
    //val result1 = target1.asInstanceOf[Boolean]
    //println(result1)

    val target2 = "1"
    // ! Error !
    // java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer
    // (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
    //val result2 = target2.asInstanceOf[Int]
    //println(result2)
    //
  }
}

【2】isInstanceOf

* Scala の データ型判定

【3】サンプル

例1:implicit Class の メソッド

* 以下の関連記事のサンプルを拡張したものを作ってみた

https://dk521123.hatenablog.com/entry/2024/07/24/120726

import ConfigType._

import scala.language.implicitConversions
import scala.util.{Failure, Success, Try}

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")
    }
  }

  implicit class ConfigTypeEx(val self: ConfigType) {
    final def getValue[T]: T = {
      val value = self match {
        case ConfigString(str) => str
        case ConfigInt(int) => int
        case ConfigBoolean(bool) => bool
        case ConfigStrings(list) => list
        case _ => throw new IllegalArgumentException("Not Supported")
      }
      // ★asInstanceOf★
      value.asInstanceOf[T]
    }
  }

  implicit class OptionConfigTypeEx(val self: Option[ConfigType]) {
    def getValueOrElse[T](default: T): T = {
      // ★isInstanceOf★
      if (self.isDefined && self.get.isInstanceOf[ConfigType])
        Try(self.get.getValue[T]) match {
          case Failure(_) => default
          case Success(value) => value
        }
      else
        default
    }
  }
}

object Hello {
  def main(args: Array[String]): Unit = {
    val mapper: Map[String, Option[ConfigType]] = Map(
      "key1" -> Some(toConfigType("Hello")),
      "key2" -> Some(toConfigType(2)),
      "key3" -> Some(toConfigType(true)),
      "key4" -> Some(toConfigType(List("value4_1", "value4_2", "value4_3"))),
      "key5" -> None
    )

    mapper.foreach { case (key: String, value: Option[ConfigType]) =>
      if (value.isEmpty) {
        println(s"${key} - ${value.getValueOrElse[String]("NoneDefault")}")
        println(s"${key} - ${value.getValueOrElse[Int](123)}")
        println(s"${key} - ${value.getValueOrElse[Boolean](true)}")
        println(s"${key} - ${value.getValueOrElse[List[String]](List("NoneA", "NoneB"))}")
      } else {
        // ここで match 使ったら、意味ないけど、、、
        value.get match {
          // String -> key1 = value1
          case ConfigString(str) => println(s"${key} - ${value.getValueOrElse[String]("default")}")
          // Int -> key2 = 2
          case ConfigInt(int) => println(s"${key} - ${value.getValueOrElse[Int](193)}")
          // Boolean -> key3 = true
          case ConfigBoolean(bool) => println(s"${key} - ${value.getValueOrElse[Boolean](true)}")
          // List[String] -> key4 = value4_1,value4_2,value4_3
          case ConfigStrings(list) => println(s"${key} - ${value.getValueOrElse[List[String]](List("C", "D"))}")
        }
      }
      println("******************")
    }
  }
}

出力結果例

key4 - List(value4_1, value4_2, value4_3)
******************
key5 - NoneDefault
key5 - 123
key5 - true
key5 - List(NoneA, NoneB)
******************
key1 - Hello
******************
key2 - 2
******************
key3 - true
******************

参考文献

https://xuwei-k.hatenablog.com/entry/20101103/1288766564
https://qiita.com/Apacher-inf/items/a680334f8d49f361ae74

関連記事

Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331
Scala ~ 基本編 / Option型 ~
https://dk521123.hatenablog.com/entry/2023/03/09/000000
Scala ~ 基本編 / ジェネリック
https://dk521123.hatenablog.com/entry/2023/03/21/003817
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/2024/07/30/155036
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 ~ 基本編 / 例外処理 ~
https://dk521123.hatenablog.com/entry/2023/10/05/000135
ScalaEnum
https://dk521123.hatenablog.com/entry/2023/01/05/000000
Scala ~ 代数的データ型 / ADT ~
https://dk521123.hatenablog.com/entry/2024/07/23/193246