Способ избежать asInstanceOf в Scala - PullRequest
0 голосов
/ 20 марта 2019

У меня есть такая иерархия черт и классов в Scala:

trait A
trait B[T] extends A {
  def v: T
}
case class C(v:Int) extends B[Int]
case class D(v:String) extends B[String]
val l:List[A] = C(1) :: D("a") :: Nil
l.foreach(t => println(t.asInstanceOf[B[_]].v))

Я не могу изменить иерархию типов или тип списка.

Есть ли лучший способ избежатьasInstanceOf [B [_]] оператор?

Ответы [ 3 ]

5 голосов
/ 20 марта 2019

Вы можете попробовать поиск по шаблону.

l.collect{case x :B[_] => println(x.v)}
4 голосов
/ 20 марта 2019

Вы можете попробовать что-то вроде этого:

for (x <- l.view; y <- Some(x).collect { case b: B[_] => b }) println(y.v)

Не требует никаких isInstanceOf или asInstanceOf и никогда не падает, даже если ваш список содержит A с, которые не B[_] с. Он также не создает длинных списков в качестве промежуточных результатов, только небольшие недолговечные Option с.


Не так кратко, но и гораздо менее удивительно:

for (x <- l) {
  x match {
    case b: B[_] => println(b.v)
    case _ => /* do nothing */
  }
}

Если бы вы могли изменить тип l на List[B[_]], это было бы предпочтительным решением.

1 голос
/ 21 марта 2019

Я думаю, что самым идеологическим способом сделать это было бы предоставить B объект экстрактора и сопоставление с шаблоном для B значений:

object B {
    def unapply[T](arg: B[T]): Some[T] =  Some(arg.v)
  }
l.collect{case B(x) => println(x)} 

Если B объявлено в источникефайл, который вы не можете изменить, может потребоваться другое имя для объекта экстрактора.

...