Сопоставление с образцом по типу Dynami c в качестве аргумента функции - PullRequest
0 голосов
/ 12 марта 2020

Я играю с scala, и я пытался создать метод, который бы возвращал список экземпляров, отфильтрованных по заданному типу (передаваемых через параметры функции):

Я попробовал следующее, но он даже не компилируется:

  trait A

  trait B extends A
  trait C extends A

  case class B1() extends B {}
  case class B2() extends B {}

  case class C1() extends C {}
  case class C2() extends C {}

  def filterByType[F <: A](list: List[A], t: Class[F]): List[F] = list flatMap {
    case f: F => Some(f)
    case _ => None
  }

  val list: List[A] = List(B1(), B2(), C1(), C2()) // type of A

  val filteredList: List[B] = filterByType(list, Class[B]) // This should return a sublist like List(B1(), B2()) and be type of B

  println(filteredList)

Есть ли способ сделать что-то подобное в scala? Каков будет правильный способ сделать это? Спасибо!

РЕДАКТИРОВАТЬ: Я также попытался передать classOf[B] безуспешно либо.

Ответы [ 2 ]

4 голосов
/ 13 марта 2020

Вы можете сделать что-то вроде этого:
(используя ClassTag )

trait A

trait B extends A
final case class B1() extends B
final case class B2() extends B

trait C extends A
final case class C1() extends C
final case class C2() extends C

import scala.reflect.ClassTag

def filterByType[F <: A :  ClassTag](list: List[A]): List[F] =
  list.collect {
    case f: F => f
  }

Что вы можете использовать следующим образом :

val list: List[A] = List(B1(), B2(), C1(), C2())

val filteredList: List[B] = filterByType[B](list)
// filteredList: List[B] = List(B1(), B2())

Примечание: Из-за стирания типа это имеет некоторые ограничения, но, похоже, оно будет работать для вашего варианта использования.
Для более общего подхода я бы создать свой собственный класс типов .

2 голосов
/ 13 марта 2020

Только с Class[F] вы можете сделать

def filterByType[F <: A](list: List[A], t: Class[F]): List[F] = list flatMap {
  case f if t.isInstance(f) => Some(t.cast(f))
  case _ => None
}

или короче, но менее эффективным

def filterByType[F <: A](list: List[A], t: Class[F]): List[F] = list flatMap { 
  x => Try { t.cast(x) }.toOption 
}

Как показывает ответ Луиса Мигеля Мехиа Суареса, сопоставление с образцом имеет особую поддержку : F доступен ClassTag[F], но не распространяется ни на что другое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...