Scala:使隐式转换 A->B 适用于 Option[A] ->选项[B] [英] Scala: Making implicit conversion A->B work for Option[A] -> Option[B]

查看:42
本文介绍了Scala:使隐式转换 A->B 适用于 Option[A] ->选项[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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆