简体   繁体   English

习惯上在序列上使用Scala隐式

[英]Using Scala implicits on a sequence, idiomatically

Suppose I am writing library code that should be easy to extend and to use without verbose syntax. 假设我正在编写应该易于扩展和易于使用且没有冗长语法的库代码。 It seems like implicit conversions can be used to avoid verbosity, as in the Scala Collections library, but I am struggling at applying it to traversables as follows. 就像在Scala Collections库中一样,隐式转换似乎可以用来避免冗长,但是我正努力将其应用于可遍历,如下所示。

I have a trait: 我有一个特点:

trait Wrapped[T]
{
  def value : T
}

Then I have the class Foo , a key class in the library. 然后,我有Foo类,这是库中的关键类。 Foo s are constructed with a list of anything that is Wrapped . Foo由包含Wrapped的所有内容的列表构成。

case class Foo[T <: Wrapped[_]](lst : Traversable[T]) {
  override def toString = lst mkString " " 
}

A common use case would be wrapping an Int so I provide a WrappedInt class: 一个常见的用例是包装一个Int所以我提供了WrappedInt类:

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

With this code, I can make a Foo like this: 使用此代码,我可以像这样创建Foo

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

I do not like the extra code to wrap here. 我不喜欢将多余的代码包装在这里。 I would like the following code to be equivalent: 我希望以下代码等效:

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

I define the following implicit: 我定义以下隐式:

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

However, it still doesn't work, my val foo has a compilation error after changing the Foo constructor parameter to implicit lst . 但是,它仍然不起作用,将Foo构造函数参数更改为implicit lst后,我的val foo出现编译错误。 The Scala book says that an implicit conversion essentially allows x + y to be changed to convert(x) + y , where convert is an implicit conversion. Scala的书说,隐式转换本质上允许x + y更改为convert(x) + y ,其中convert是隐式转换。 It seems to me like I have the same exact case, one conversion of one parameter here is enough. 在我看来,我有相同的确切情况,这里一个参数的一次转换就足够了。 I verify by doing this: 我通过这样做验证:

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

Why is my implicit not being applied? 为什么我的隐式不被应用? And is there a different, more idiomatic way in current Scala to let Foo be constructed with less code? 在当前的Scala中,有没有其他更惯用的方式可以用更少的代码构造Foo

EDIT: Adding import Conversions._ does not help and should, if I understand correctly, not be necessary because this example is in one file. 编辑:添加import Conversions._没有帮助,并且,如果我理解正确,应该没有必要,因为此示例在一个文件中。

Specific compiler errors I get are these: 我得到的特定编译器错误是:

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]

Specifying the type to help with type inference, like this: 指定类型以帮助进行类型推断,如下所示:

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

gives a message for each int like 给每个int消息

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

You can specify an implicit conversion in foo's constructor (what once was a view bound). 您可以在foo的构造函数中指定一个隐式转换(以前是视图绑定)。 You have to specify that the collection elements are "viewable" as their wrapped versions, not the collection itself. 您必须指定集合元素作为其包装版本是“可见的”,而不是集合本身。

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)) 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM