💻
【Scala】Optionと非Optionを比較する時の話
バージョン
Scala 2.13.1
今更感ありますが
val numOpt = Some(3)
val num3 = 3
val num4 = 4
val str = "str"
numOptと他の値を比較する際、
numOpt.contains(num3) // true
numOpt.contains(num4) // false
numOpt.contains(str) // false ※型が違うもの同士を比較しているのでそもそもコンパイルエラーで弾きたい
numOpt.contains(str)みたいなコードを書いてしまってバグらせてしまったことがありました。
なぜコンパイルエラーにならないのか
Option.containsについて見てみると、型パラメータA1については、AはA1のサブタイプであるという制約になっています。
https://www.scala-lang.org/api/2.13.3/scala/Option.html#containsA1%3E:A:Boolean
final def contains[A1 >: A](elem: A1):
型パラメータを特に指定していないのでコンパイラがA1をAnyだと推論しています。
なので今回の例の場合だと以下のようにすればエラーになってくれます。
numOpt.contains[Int](str)
エラー
type mismatch;
[error] found : String
[error] required: Int
[error] numOpt.contains[Int](str)
喰らえ! -Xlint:infer-any
とはいえ毎回型パラメータを指定するのも面倒です。Anyに推論されるのをやめさせたいですね。
XlintとはScalaのコンパイラscalacのオプションです。
build.sbt
に設定しましょう
scalacOptions ++= Seq(
"-Xlint:infer-any",
)
numOpt.contains(str)をコンパイルすると以下の警告を出してくれます。
a type was inferred to be `Any`; this may indicate a programming error.
エラーにしたい場合は-Xfatal-warnings
も指定しよう。
scalacOptions ++= Seq(
"-Xlint:infer-any",
"-Xfatal-warnings",
)
Xlintについて
infer-anyだけではなく様々なlintingのオプションがあります(-Xlintとだけ指定すればそれらすべてをやってくれます。)
一覧は https://docs.scala-lang.org/overviews/compiler-options/index.html#Advanced_Settings
参考
-Xlint, -Xfatal-warnings, そして Scalafix を用いた Scala の厳格化 | eed3si9n
Discussion