我有一个异类List,如下所示:
val l = List(1, "One", true)
Run Code Online (Sandbox Code Playgroud)
我需要通过仅提取属于给定类的对象来过滤其对象.为此我写了一个非常简单的方法:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (_.asInstanceOf[AnyRef].getClass() == c)
Run Code Online (Sandbox Code Playgroud)
请注意,我有义务将显式转换添加到AnyRef以避免此编译问题:
error: type mismatch;
found : _$1 where type _$1
required: ?{val getClass(): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method any2stringadd in object Predef of type (x: Any)scala.runtime.StringAdd
and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
are possible conversion functions from _$1 to ?{val getClass(): ?}
l filter (_.getClass() == c)
Run Code Online (Sandbox Code Playgroud)
但是通过这种方式调用:
filterByClass(l, classOf[String])
Run Code Online (Sandbox Code Playgroud)
按预期返回:
List(One)
Run Code Online (Sandbox Code Playgroud)
但当然同样不起作用,例如,使用Int,因为它们扩展Any而不是AnyRef,所以通过调用:
filterByClass(l, classOf[Int])
Run Code Online (Sandbox Code Playgroud)
结果只是空List.
有没有办法使我的filterByClass方法工作,即使使用Int,Boolean和所有其他类扩展Any?
Mor*_*itz 13
该collect方法已经做了你想要的.例如,收集Int你可以写的集合中的所有s
xs collect { case x: Int => x }
Run Code Online (Sandbox Code Playgroud)
这当然只有在您对类型进行硬编码时才有效,但由于原语的处理方式与引用类型不同,实际上这样做更好.使用某些类型类可以让您的生活更轻松:
case class Collect[A](collect: PartialFunction[Any,A])
object Collect {
implicit val collectInt: Collect[Int] = Collect[Int]({case x: Int => x})
// repeat for other primitives
// for types that extend AnyRef
implicit def collectAnyRef[A <: AnyRef](implicit mf: ClassManifest[A]) =
Collect[A]({ case x if mf.erasure.isInstance(x) => x.asInstanceOf[A] })
}
def collectInstance[A : Collect](xs: List[_ >: A]) =
xs.collect(implicitly[Collect[A]].collect)
Run Code Online (Sandbox Code Playgroud)
然后你甚至可以在不传递Class[A]实例的情况下使用它:
scala> collectInstance[Int](l)
res5: List[Int] = List(1)
scala> collectInstance[String](l)
res6: List[String] = List(One)
Run Code Online (Sandbox Code Playgroud)
尽管我的解决方案可能不如这个优雅,但我发现我的解决方案更快更容易。我刚刚定义了一个这样的方法:
private def normalizeClass(c: Class[_]): Class[_] =
if (classOf[AnyRef].isAssignableFrom((c))) c
else if (c == classOf[Int]) classOf[java.lang.Integer]
// Add all other primitive types
else classOf[java.lang.Boolean]
Run Code Online (Sandbox Code Playgroud)
因此,通过在我以前的 filterByClass 方法中使用它,如下所示:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (normalizeClass(c).isInstance(_))
Run Code Online (Sandbox Code Playgroud)
调用:
filterByClass(List(1, "One", false), classOf[Int])
Run Code Online (Sandbox Code Playgroud)
刚刚返回
List(1)
Run Code Online (Sandbox Code Playgroud)
正如预期的那样。