惯用地在序列上使用 Scala 隐式
Using Scala implicits on a sequence, idiomatically
假设我正在编写应该易于扩展和使用而无需冗长语法的库代码。似乎可以使用隐式转换来避免冗长,就像在 Scala Collections 库中一样,但我正在努力将其应用于可遍历对象,如下所示。
我有一个特点:
trait Wrapped[T]
{
def value : T
}
然后我有 class Foo
,图书馆里的一把钥匙 class。 Foo
由 Wrapped
.
的任何列表构成
case class Foo[T <: Wrapped[_]](lst : Traversable[T]) {
override def toString = lst mkString " "
}
一个常见的用例是包装一个 Int
所以我提供一个 WrappedInt
class:
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))
为每个整数给出一条消息,如
type mismatch; found : Int(1) required: WrappedInt
您可以在 foo 的构造函数中指定隐式转换(曾经是视图绑定)。您必须指定集合元素 "viewable" 作为它们的包装版本,而不是集合本身。
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))
假设我正在编写应该易于扩展和使用而无需冗长语法的库代码。似乎可以使用隐式转换来避免冗长,就像在 Scala Collections 库中一样,但我正在努力将其应用于可遍历对象,如下所示。
我有一个特点:
trait Wrapped[T]
{
def value : T
}
然后我有 class Foo
,图书馆里的一把钥匙 class。 Foo
由 Wrapped
.
case class Foo[T <: Wrapped[_]](lst : Traversable[T]) {
override def toString = lst mkString " "
}
一个常见的用例是包装一个 Int
所以我提供一个 WrappedInt
class:
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))
为每个整数给出一条消息,如
type mismatch; found : Int(1) required: WrappedInt
您可以在 foo 的构造函数中指定隐式转换(曾经是视图绑定)。您必须指定集合元素 "viewable" 作为它们的包装版本,而不是集合本身。
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))