Scala:使隐式转换 A->B 适用于 Option[A] ->选项[B] [英] Scala: Making implicit conversion A->B work for Option[A] -> Option[B]
问题描述
我正在尝试编写一个函数,当它们以通用方式包装在 Option 中时,我为对象 A -> 对象 B 重新使用隐式转换,以便 Option[A] -> Option[B] 转换也有效.
I'm trying to write a function which re-uses the implicit conversions which I have for Object A -> Object B when they are wrapped in an Option in a generic way so that Option[A] -> Option[B] conversions also work.
我想到的是:
implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_))
这在我将 Some(..) 分配给一个值时有效,但在分配 Option val 时无效;请参阅以下控制台输出:
This works when I assign a Some(..) to a value but not when I assign an Option val; see the following console output:
scala> trait T
defined trait T
scala> case class Foo(i: Int) extends T
defined class Foo
scala> case class Bar(i: Int) extends T
defined class Bar
scala> implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
fromFooToBar: (f: Foo)Bar
scala> implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
fromBarToFoo: (b: Bar)Foo
scala> implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_))
fromOptionToOption: [A, B](from: Option[A])(implicit conversion: (A) => B)Option[B]
scala> val foo: Option[Foo] = Some(Bar(1))
foo: Option[Foo] = Some(Foo(1))
// THIS WORKS as expected
scala> val fooOpt = Some(Foo(4))
fooOpt: Some[Foo] = Some(Foo(4))
scala> val barOpt2: Option[Bar] = fooOpt
<console>:16: error: type mismatch;
found : Some[Foo]
required: Option[Bar]
val barOpt2: Option[Bar] = fooOpt
^
//THIS FAILS.
我真的没有看到第一次和第二次转换之间的区别.不知何故,它不会调用后者中的隐式转换.我想这与类型系统有关,但我还看不出是怎么回事.有任何想法吗?-阿尔伯特(我在 Scala 2.9.1)
I don't really see the difference between the first and second conversion. Somehow it doesn't invoke the implicit conversion in the latter. I guess it has something to do with the type system, but I can't see how just yet. Any ideas? -Albert (I'm on scala 2.9.1)
推荐答案
线索如下:
scala> val fooOpt: Option[Bar] = Option(Foo(1))
fooOpt: Option[Bar] = Some(Bar(1))
还有一个:
scala> implicit def foobar(x: String): Int = augmentString(x).toInt
foobar: (x: String)Int
scala> val y: Option[String] = Option(1)
y: Option[String] = Some(1)
scala> val y: Option[Int] = Option("1")
y: Option[Int] = Some(1)
看起来像是一个合法的奇怪错误.我会打开一个较小的测试用例并打开一个问题(或在 JIRA 中搜索一个).
Looks like a legitimately odd bug. I'd pop open a smaller test case and open an issue (or search for one in JIRA).
顺便说一句:
您可以使用一些类别理论来处理许多不同类型的Option-ish"事物.
You could use some category theory to handle lots of different types of "Option-ish" things.
package object fun {
trait Functor[Container[_]] {
def fmap[A,B](x: Container[A], f: A => B): Container[B]
}
object Functor {
implicit object optionFunctor extends Functor[Option] {
override def fmap[A,B](x: Option[A], f: A => B): Option[B] = x map f
}
// Note: With some CanBuildFrom magic, we can support Traversables here.
}
implicit def liftConversion[F[_], A, B](x: F[A])(implicit f: A => B, functor: Functor[F]): F[B] =
functor.fmap(x,f)
}
这有点高级,因为您将一些类别理论 FP 映射到问题上,但它是根据需要将隐式对话提升到容器中的更通用的解决方案.请注意它们如何通过使用一种隐式对话方法进行链接,该方法采用一个更有限的隐式参数.
That's a bit more advanced, as you're mapping some category theory FP onto the problem, but it's a more general solution to lift implicit conversations into containers as needed. Notice how they chain by using one implicit conversation method that takes a more limited implicit argument.
此外,这应该使示例工作:
ALSO, this should make the examples work:
scala> val tmp = Option(Foo(1))
tmp: Option[Foo] = Some(Foo(1))
scala> val y: Option[Bar] = tmp
y: Option[Bar] = Some(Bar(1))
并使您对Some
的使用更加危险:
And make your usage of Some
more dangerous:
scala> val tmp = Some(Foo(1))
tmp: Some[Foo] = Some(Foo(1))
scala> val y: Option[Bar] = tmp
<console>:25: error: could not find implicit value for parameter functor: fun.Functor[Some]
val y: Option[Bar] = tmp
^
这告诉您 variance 很关键,并且会与隐式交互.我的猜测是您遇到了一个非常罕见的、可能很难修复的错误,而使用其他技术可以避免这些错误.
That's telling you that variance is critical, and interacts with implicits. My guess is you ran into a very rare, probably hard to fix bug that can be avoided using other techniques.
这篇关于Scala:使隐式转换 A->B 适用于 Option[A] ->选项[B]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!