Когда использовать isInstanceOf и когда использовать match-case-statement (в Scala)?

sealed class A
class B1 extends A    
class B2 extends A

Предполагая, что у нас есть список объектов класса A:   val l: Список [A] = Список (новый B1, новый B2, новый B1, новый B1)

И мы хотим отфильтровать элементы типа B1. Тогда нам нужен предикат и он может использовать следующие две альтернативы:

l.filter(_.isInstanceOf[B1])

или

l.filter(_ match {case b: B1 => true; case _ => false})

Лично мне больше нравится первый подход, но я часто читаю, нужно использовать инструкцию match-case чаще (по причинам, которые я не знаю).

Поэтому возникает вопрос: существуют ли недостатки использования isInstanceOf вместо инструкции match-case? Когда следует использовать какой подход (и какой подход следует использовать здесь и почему)?

Ответ 1

Вы можете так фильтровать:

l.collect{ case x: B1 => x }

Это более читаемо, ИМО.

Ответ 2

Преимущество match-case заключается в том, что вам не нужно бросать объект, если вы хотите выполнять на нем операции, которые зависят от его более узкого типа.

В следующем фрагменте использование isInstanceOf кажется прекрасным, поскольку вы не выполняете такую ​​операцию:

if (obj.isInstanceOf[A]) println(obj)

Однако, если вы выполните следующее:

if (obj.isInstanceOf[A]) {
  val a = obj.asInstanceOf[A]
  println(a.someField) // someField is declared by A
}

то я был бы сторонником использования match-case:

obj match {
  case a: A => println(a.someField)
  case _ =>
}

Немного досадно, что вам нужно включить "в противном случае" -case, но использование collect (как намечено ом-ном-ном) могло бы помочь, по крайней мере, если вы работаете с коллекциями, наследуемыми от Seq:

collectionOfObj.collect{ case a: A => a}.foreach(println(_.someField))

Ответ 3

Нет проблем с использованием isInstanceOf, если вы не используете asInstanceOf.

Код, который использует оба метода, является хрупким, потому что проверка и литье являются отдельными действиями, тогда как при использовании соответствия у вас есть одно действие, выполняющее оба.

Ответ 4

Нет разницы

cat t.scala:

class A {
  def x(o: AnyRef) = o.isInstanceOf[A]
  def y(o: AnyRef) = o match {
    case s: A => true
    case _ => false
  }
}

$scalac -print t.scala

[[syntax trees at end of cleanup]]// Scala source: t.scala
package <empty> {
  class A extends java.lang.Object with ScalaObject {
    def x(o: java.lang.Object): Boolean = o.$isInstanceOf[A]();
    def y(o: java.lang.Object): Boolean = {
      <synthetic> val temp1: java.lang.Object = o;
      temp1.$isInstanceOf[A]()
    };
    def this(): A = {
      A.super.this();
      ()
    }
  }
}