首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何定义一个方法,该方法接受属于某个类型类的类型的异构对象序列?

如何定义一个方法,该方法接受属于某个类型类的类型的异构对象序列?
EN

Stack Overflow用户
提问于 2014-08-07 23:34:42
回答 2查看 185关注 0票数 1

有一种类型可以通过一组特定的受限类型来参数化:

代码语言:javascript
复制
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
  override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
  override def f(t: Int) = List(t,t,t)
}

现在,我可以定义一个函数,该函数接受特定类型的集合并对其进行处理:

代码语言:javascript
复制
def consume[T : Base](xs: Seq[T]) =
  xs.map(x => implicitly[Base[T]].f(x).mkString("-"))

当然是以一种类型安全的方式。

如果我还不是很清楚,下面是我想要的:

代码语言:javascript
复制
consume(Seq(1,"asd", 3)) // => Seq("1-1-1", "a-s-d", "3-3-3")

我确信我可以用shapeless的HList实现它,但是核心Scala呢?无论如何,将shapeless标记放在功能倾向的人愿意提供帮助的情况下。

EN

回答 2

Stack Overflow用户

发布于 2015-07-29 07:48:38

代码语言:javascript
复制
import shapeless._
import ops.hlist.Mapper
import ops.hlist.ToList

trait Base[T] { def f(t: T): List[T] }

implicit object StringBase extends Base[String] {
  override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
  override def f(t: Int) = List(t,t,t)
}
object base extends Poly1 {
    implicit def forBase[A : Base] = at[A](x => implicitly[Base[A]].f(x))
}

def consume[T <: HList, Inter <: HList](xs: T)
(implicit
    mapBase: Mapper.Aux[base.type, T, Inter],
    interToList: ToList[Inter, List[Any]]): Seq[String] = {
    xs.map(base).toList.map(_.mkString("-"))
}

两个关键部分:

  1. object base extends Poly1:这是一个只在具有Base类型类实例的类型上定义的多态函数。它在它的参数上调用Base.f
  2. consume中的隐式和类型参数: params是我们的输入HList类型。Inter是一个中间类型变量,它是在T.
  3. mapBase: Mapper.Aux[base.type, T, Inter]上映射base的结果的输出类型:这证明如果我们在T上映射base,就会得到Inter。我们需要它来调用传入的hlist上的.map。通过将其放入我们的隐式列表中,我们只需要在调用函数时它存在。Shapeless将在可能的情况下为我们生成此代码。如果不能,很可能意味着您忘记了为T
  4. interToList: ToList[Inter, List[Any]]中的类型定义Base实例:这是您可以将HList Inter转换为List[List[Any]]的证据。因此,在Inter中的所有类型中,List[Any]必须是最小的上界类型。同样,通过将它放在输入隐式中,我们只需要shapeless可以为我们生成它。这只是一个样板,用来向编译器证明我们可以调用toList并获得List[List[Any]]。在我的经验sadly.

中,我还没有找到一种方法来避免这个和Inter变量

现在,多亏了所有这些隐含,我们只需调用xs.map(base)来获得一个应用了适当Base.f的HList。然后我们调用.toList来获取一个List[List[Any]]。然后我们的Seq[String]就出来了!

下面是它在REPL中的工作原理:

代码语言:javascript
复制
scala> consume(1 :: "asd" :: 3 :: HNil)
res0: Seq[String] = List(1-1-1, a-s-d, 3-3-3)
票数 1
EN

Stack Overflow用户

发布于 2014-08-08 01:25:24

这里是消费方法的肮脏的黑客攻击。不是超级类型的安全和好,但作为一个解决办法可能会很好。

代码语言:javascript
复制
  trait Base[T] { def f(t: T): List[T] }
  implicit object StringBase extends Base[String] {
    override def f(t: String) = t.toList.map(c => String.valueOf(c))
  }
  implicit object IntBase extends Base[Int] {
    override def f(t: Int) = List(t,t,t)
  }

  case class Consumable[T](v: T, base: Base[T])

  implicit def toConsumable[T](v: T)(implicit base: Base[T], ev: ClassTag[T]) =
    Consumable(v, base)

  def consume(xs: Consumable[_]*) =
    xs.map(x => x.base.asInstanceOf[Base[Any]].f(x.v).mkString("-"))

  println(consume(1, 2, 3))
  println(consume("a", "b", "c"))
  println(consume(1, 2, "a", "b", "c"))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25186552

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档