使用Scala会对序列进行暗示

时间:2016-03-13 12:38:23

标签: scala implicit-conversion implicit

假设我正在编写应该易于扩展且无需详细语法即可使用的库代码。看起来像隐式转换可以用来避免冗长,就像在Scala Collections库中一样,但我正在努力将它应用于遍历,如下所示。

我有一个特点:

trait Wrapped[T]
{
  def value : T
}

然后我有了类Foo,它是库中的一个关键类。 Foo是使用Wrapped

的任何列表构建的
case class Foo[T <: Wrapped[_]](lst : Traversable[T]) {
  override def toString = lst mkString " " 
}

一个常见的用例是包裹Int所以我提供了WrappedInt类:

case class WrappedInt(value : Int) extends Wrapped[Int]

使用此代码,我可以像这样Foo

val wrappedInts = Seq(1, 2, 3, 4) map { new WrappedInt(_) }
val someFoo = Foo(wrappedInts)

我不喜欢在这里包装的额外代码。我希望以下代码是等效的:

val foo = Foo(Seq(1, 2, 3, 4)) //should be a Foo[WrappedInt] - gives error

我定义了以下内容:

object Conversions {
  implicit def intsToWrapped(lst : Traversable[Int]) = lst map { new WrappedInt(_) }
}

但是,它仍然不起作用,我的val foo在将Foo构造函数参数更改为implicit lst后出现编译错误。 Scala书中说隐式转换基本上允许x + y更改为convert(x) + y,其中convert是隐式转换。在我看来,我有相同的确切情况,这里一个参数的一次转换就足够了。我通过这样做验证:

val foo = Foo(Conversions.intsToWrapped(Seq(1, 2, 3, 4)))

为什么我的隐含未被应用?在当前的Scala中是否有一种不同的,更惯用的方式来让Foo用更少的代码构建?

编辑:添加import Conversions._没有帮助,如果我理解正确,则没有必要,因为此示例位于一个文件中。

我得到的具体编译器错误是:

val foo = Foo(Seq(1, 2, 3, 4))


inferred type arguments [Int] do not conform to method apply's type parameter bounds [T <: Wrapped[_]]
type mismatch; found : Seq[Int] required: Traversable[T]

指定帮助类型推断的类型,如下所示:

val foo = Foo[WrappedInt](Seq(1, 2, 3, 4))

为每个int提供一条消息,如

type mismatch; found : Int(1) required: WrappedInt

1 个答案:

答案 0 :(得分:2)

您可以在foo的构造函数中指定隐式转换(曾经是视图边界)。您必须指定集合元素是&#34;可查看的&#34;作为他们的包装版本,而不是集合本身。

trait Wrapped[T] {
  def value : T
}

// you can specify bounds on W if you want to be able to do something specific on the values, e.g. W <: MyClass
case class Foo[T, W](lst : Traversable[T])(implicit asWrapped: T => Wrapped[W]) {
  override def toString = lst.map(_.value) mkString " "
}

case class WrappedInt(value : Int) extends Wrapped[Int]

// This is your implicit conversion from Int to WrappedInt
implicit def intToWrapped(x : Int): WrappedInt = WrappedInt(x)

val wrappedInts = Seq(1, 2, 3, 4) map { new WrappedInt(_) }
val someFoo = Foo(wrappedInts)
val foo = Foo(Traversable(1, 2, 3, 4))