Scala полиморфные методы - {case x: T => x} возвращает все типы - PullRequest
1 голос
/ 08 октября 2019

Я не понимаю, почему в Scala полиморфный метод не работает так, как я ожидал.

позволяет иметь метод:

def sth[T](list: Iterable[Any]): List[T] = {
list.collect({case s:T => s}).toList
}

not Я хотел бы получить только Boolean из моего списка. поэтому я написал бы:

val out = sth[Boolean](List(true, false, 2.0, 2, 4, 12.3))

То, что я ожидаю, равно List(true, false), и IntelIJ показывает мне, что out является экземпляром: List[Boolean] НО, что этот метод возвращает мне, является моим списком ввода: List(true, false, 2.0, 2, 4, 12.3)

Я тоже пробовал с list.filter(s => s.isInstanceOf[T]), но получил тот же результат.

enter image description here

Я немного запутался. Можете ли вы объяснить мне, что я сделал не так?

1 Ответ

8 голосов
/ 08 октября 2019

Из-за стирания типа чек

case s:T => ...

становится чем-то вроде

if (s.isInstanceOf[Object]) ...

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

 warning: abstract type pattern T is unchecked since it is eliminated by erasure
    list.collect({case s:T => s}).toList

Попробуйте предоставить ClassTag примерно так

import scala.reflect.ClassTag

def collect[T: ClassTag](list: Iterable[Any]): List[T] = {
  list.collect({ case s: T => s }).toList
}

collect[Boolean](List(true, false, 2.0, 2, 4, 12.3))
collect[Double](List(true, false, 2.0, 2, 4, 12.3))

, который выдает

res0: List[Boolean] = List(true, false)
res1: List[Double] = List(2.0, 12.3)

, который работает из-за некоторой магии компилятора, объясненной здесь .

Вот наше собственное решение класса типов

trait Collectable[T] {
  def collect(list: Iterable[Any]): List[T]
}

object Collectable {
  def collect[T](list: Iterable[Any])(implicit ev: Collectable[T]): List[T] =
    ev.collect(list)

  implicit val booleanCollect: Collectable[Boolean]  = 
    (list: Iterable[Any]) => list.collect({ case s: Boolean => s }).toList

  implicit val doubleCollect: Collectable[Double] = 
    (list: Iterable[Any]) => list.collect({ case s: Double => s }).toList
}

import Collectable._

collect[Boolean](List(true, false, 2.0, 2, 4, 12.3))
collect[Double](List(true, false, 2.0, 2, 4, 12.3))

, которое выдает

res0: List[Boolean] = List(true, false)
res1: List[Double] = List(2.0, 12.3)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...