Приведение null к экземпляру case-класса в Scala

У меня есть фрагмент кода, который полагается на существование произвольного элемента определенного класса case для работы с полями класса. Есть некоторые options, и хотя почти каждый блог Scala рекомендует никогда не использовать null, это не кажется ужасной идеей в программировании на уровне типов (например, этот ответ: https://stackoverflow.com/a/4443972/1650448). Однако этот код, напрямую приводящий null к конкретному case-классу, не работает и не выдает ошибку, и мне интересно, почему.

trait V {}
case class W(x: Int) extends V

val y = null.asInstanceOf[W]

y match {
  case w:W => println("null cast to W is a W")
  case _ => println("null cast to W is NOT a W")
}

// prints "null cast to W is NOT a W"

y match {
  case v:V => println("null cast to W is a V")
  case _ => println("null cast to W is NOT a V")
}

// prints "null cast to W is NOT a V"

val z = W(1)

z match {
  case w:W => println("instantiated W is a W")
  case _ =>  println("instantiated W is NOT a W")
  }

// prints "instantiated W is a W"

z match {
  case v:V =>  println("instantiated W is a V")
  case _ =>  println("instantiated W is NOT a V")
}

// prints "instantiated W is a V"


person Michael K    schedule 12.11.2019    source источник
comment
Это не программирование на уровне типов, поэтому рекомендуется избегать null. Используйте Option.   -  person Tim    schedule 12.11.2019


Ответы (2)


Потому что Шаблоны типов определяются так:

  • Ссылка на класс C, p.C или T#C. Этот шаблон типа соответствует любому ненулевому экземпляру данного класса.

Итак: null — это совершенно правильное значение типа W; но он не будет соответствовать шаблону w: W.

И главная причина, по которой он не совпадает, именно

У меня есть фрагмент кода, который полагается на существование произвольного элемента определенного класса case для работы с полями класса.

поэтому, когда вы сопоставляете с w: W, вы хотите знать, что его поля и методы доступны. Но для null это не так.

person Alexey Romanov    schedule 12.11.2019

Приведение изменяет тип времени компиляции, а не тип времени выполнения. Сопоставление с образцом проверяет тип среды выполнения. На самом деле сопоставление с образцом case class даже имеет явную проверку на null; см. Почему существует проверка `null` в реализации метода `unapply` для классов case? (хотя эта проверка не влияет на ваш случай, так как вы используете шаблон типа).

Кроме того, даже если бы не проблема сопоставления с образцом, вы не смогли бы «работать с полями класса» без получения исключения NullPointerException.

person Brian McCutchon    schedule 12.11.2019