型判定とキャスト : kotlin

型判定とキャスト

is演算子と!演算子による型判定

※これis演算子と否定の!演算子の組み合わせだから、こういう表現の方が正しいような気がするけれども、どうだろうか(´・ω・`)?

is演算子またはその否定形式である!isを使用して、実行時にオブジェクトが特定の型に準拠しているかどうかを確認できます:

if (obj is String) {
  print(obj.length)
}

if (obj !is String) { // !(obj is String)と同じです。
  print("Not a String")
}
else {
  print(obj.length)
}

スマートキャスト

Kotlinでは多くの場合、キャスト演算子を明示的に使用する必要はありません。コンパイラは不変の値に対するis演算子の使用を探知し、必要に応じて(安全な)キャストを自動的に挿入するからです:

fun demo(x: Any) {
  if (x is String) {
    print(x.length) // xは自動的にStringにキャストされます。
  }
}

コンパイラは、否定判定の結果がReturnになる場合にキャストが安全になること(キャストが発生しないこと?)を理解するほどに賢いです: ←※いろんな翻訳サイトを使ってもいまいち翻訳しきれなかったのでちょっと超訳(´・ω・`)シドニィ

if (x !is String) return
  print(x.length) // xは自動的にStringにキャストされます。

また&&および||演算子の右側でも:

  // `||`の右側でxは自動的に文字列にキャストされます。…(1)(2)
  if (x !is String || x.length == 0) return

  // `&&`の右側でxは自動的に文字列にキャストされます。…(2)
  // 同上
  if (x is String && x.length > 0)
      print(x.length) // xは自動的にStringにキャストされます。

(1)原文に即して翻訳したけれども、コンパイラはis判定でtrue(または!is判定でfalse)で、後の行でその変数を使用する場合にのみ即時キャストするのか、使用直前でキャストするのかでここの文言が変わって来るような気がする。そういう意味合いにおいてはいつキャストされるかということを明示した方がいいのではなかろうか?
(2)stringじゃなくてStringだな。ここの二箇所だけstringになってる。どうでもいいけどw

このようなスマートキャストは、when式とwhileループでも機能します。:

when (x) {
  is Int -> print(x + 1)
  is String -> print(x.length + 1)
  is IntArray -> print(x.sum())
}

コンパイラが判定時と実際の使用時の間で変数が不変であることを保証できない場合、スマートキャストは機能しないことに注意してください。より具体的には、スマートキャストは次のルールに従って適用されます。:

valローカル変数 - 常時;
valプロパティ - プロパティがprivateまたはinternalである場合、またはプロパティが宣言されているのと同じモジュールで判定が実行される場合。スマートキャストは、openのついた継承可能なプロパティまたはカスタムゲッターがあるプロパティには適用されません。
varローカル変数 - 変数が判定時と実際の使用時の間で変更されておらず、それを変更するラムダに捕捉されていない場合。
※Kotlinのラムダ式はラムダ式の中から、外側の変数の値を変更することができ、これを捕捉できると表現する模様。まあ詰まるところ変更されない限りということだろうか。https://maku77.github.io/kotlin/basic/lambda.html
varプロパティ- 不可。(このvarプロパティは他のコードによっていつでも変更されうる為。)


"アンセーフ(安全ではない)"キャスト演算子

通常、キャストが不可能な場合、キャスト演算子は例外をスローします。したがって、私たちはそれをアンセーフ(安全ではない)と呼びます。 Kotlinでの安全ではないキャストは、中置演算子 asによって行われます("演算子の優先順位"を参照)。:

val x: String = y as String

この型はnull許容ではないため、nullをStringにキャストできないことに注意してください。つまり、yがnullの場合、上記のコードは例外をスローします。 Javaキャストのセマンティクスに一致させるには、キャストの右側にnull許容型が必要です。
※キャストの右側だけじゃなくて左側の宣言の型にも必要なんじゃ? それとも型の右側という意味?

val x: String? = y as String?

"セーフ(安全な)"(null許容)キャスト演算子

例外がスローされるのを避けるために、失敗時にnullを返すセーフキャスト演算子as?を使用できます。

val x: String? = y as? String

as?の右側が非null型の文字列であることに関わらず、キャストの結果はnull許容型です。