gpt4 book ai didi

scala - 用于从集合中检索特定类型项的通用强类型 Scala 方法

转载 作者:行者123 更新时间:2023-12-03 21:28:21 31 4
gpt4 key购买 nike

假设我有这个类:

class Example {
val list = List(new Apple(), new Orange(), Banana());
def getIfPresent[T <: Fruit] : Option[T] = list.collectFirst { case x : T => x }
}

你可以这样使用它:

val example = new Example();
match example.getIfPresent[Apple] {
case Some(apple) => apple.someAppleSpecificMethod();
case None => println("No apple");
}

当然,由于类型删除,这在 JVM 中不起作用。 getIfPresent 仅匹配 collectFirst 部分函数中的 Fruit 类型,而不是调用中指定的实际类型。

我试图了解类型标签和类标签,但真的不知道如何实现上述方法。我看到的例子试图做非常不同的事情。我如何使用 TypeTag 或其他我不知道的机制来实现我想要的方法?


编辑:下面 m-z 的回答是完整的解决方案,但这是我的示例代码的样子:

class Example {
val list = List(new Apple(), new Orange(), Banana());
def getIfPresent[T <: Fruit : ClassTag] : Option[T] = list.collectFirst { case x : T => x }
}

只需要添加: ClassTag!

最佳答案

您可以在一定程度上使用 ClassTag 来做到这一点。

import scala.reflect.ClassTag

// Modify to apply whatever type bounds you find necessary
// Requires Scala ~2.11.5 or greater (not sure of the exact version, but 2.11.1 does not work, and 2.11.5 does)
def findFirst[A : ClassTag](list: List[Any]): Option[A] =
list collectFirst { case a: A => a }

val l = List(1, "a", false, List(1, 2, 3), List("a", "b"))

scala> findFirst[Boolean](l)
res22: Option[Boolean] = Some(false)

scala> findFirst[Long](l)
res23: Option[Long] = None

但是 ClassTag 有一些注意事项,因为它只会匹配类,而不匹配类型:

scala> findFirst[List[String]](l)
res24: Option[List[String]] = Some(List(1, 2, 3)) // No!

您可以使用 TypeTag 来解决这个问题,但它不适用于 List[Any]。这是一个可能的(有点丑陋的)技巧:

import scala.reflect.runtime.universe.{typeOf, TypeTag}

case class Tagged[A : TypeTag](a: A) {
def tpe = typeOf[A]
}

implicit class AnyTagged[A : TypeTag](a: A) {
def tag = Tagged(a)
}

def findFirst[A : TypeTag](list: List[Tagged[_]]): Option[A] =
list collectFirst { case tag @ Tagged(a) if(tag.tpe =:= typeOf[A]) => a.asInstanceOf[A] }

我能想到的保留每个元素的 TypeTag 的唯一方法就是用包装类来保留它。所以我必须像这样构建列表:

val l = List(1.tag, "a".tag, false.tag, List(1, 2, 3).tag, List("a", "b").tag)

但它有效:

scala> findFirst[List[String]](l)
res26: Option[List[String]] = Some(List(a, b))

可能有一种更优雅的方式来构造这样一个带有 TypeTag 的列表。


为了好玩,您也可以尝试使用 shapeless 来做到这一点使用 HListselect。不同之处在于,select 不是返回 Option[A],而是返回 A(您想要的类型),但是如果 HList 不包含 A它不会编译

import shapeless._

val l = 1 :: "a" :: false :: List(1, 2, 3) :: List("a", "b") :: HNil

scala> l.select[Boolean]
res0: Boolean = false

scala> l.select[Boolean]
res1: Boolean = false

scala> l.select[List[String]]
res2: List[String] = List(a, b)

scala> l.select[Long]
<console>:12: error: Implicit not found: shapeless.Ops.Selector[shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.::[List[Int],shapeless.::[List[String],shapeless.HNil]]]]], Long]. You requested an element of type Long, but there is none in the HList shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.::[List[Int],shapeless.::[List[String],shapeless.HNil]]]]].
l.select[Long]
^

关于scala - 用于从集合中检索特定类型项的通用强类型 Scala 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32464929/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com