我想表达如下:
val input: Option[String] = Option("123")
val longOption1: Option[Long] = input
println(longOption1)
// Some(123)
val longOption2: Option[Long] = Option("abc")
println(longOption2)
// None
我有过这样的尝试:
object OptionalConverter {
implicit val string2Long = (s: String) => s.toLong
implicit val string2Int = (s: String) => s.toInt
implicit def convert[A, B](input: Option[A])(implicit mapper: A => B): Option[B] = input.flatMap(i => Try(mapper(i)).toOption)
}
但是它不工作,我有点卡住了。
我不确定我的用法是否可行,或者我是否必须使它至少沿着val result = convert[Option[Long]](Option("123"))
的行才能编译。
任何提示赞赏!
2条答案
按热度按时间6kkfgxo01#
它不起作用的原因是你有冲突的暗示。因为有不止一种方法可以将
Option[String]
转换为Option[Int]
,所以编译器无法知道应该使用哪种方法,也不会使用任何方法。你可以在使用
-Yno-predef
编译器选项时看到它:(see:Scastie)。
这段代码编译并打印您所期望的内容。然而,在这方面,
implicit val string2Int: String => Int
,它将停止工作-也许,因为你可以将Long
转换为Int
(反之亦然),这个原生的implicit A => B
变得模糊不清。string2Int
注解掉,但删除了-Yno-predef
,则从scala.Predef
进行隐式转换将与string2Long
发生冲突,并使其变得不明确Predef
而注解掉string2int
和string2Long
,它也不起作用。这突出了隐式转换有多少陷阱,以及它们以不可预测的方式发生冲突的容易程度(这并不像它们导致编译代码不应该编译,因为它们的混合导致不必要的行为)。
出于这个原因,最好使用带有类型类的某种扩展方法,因为它将基于隐式的行为约束到单个用例中,这有助于调试和驯服行为。
ubbxdtey2#
使用非常一般的隐式几乎总是一个坏主意,因为它可能导致非常不可预测的结果。
与其使用裸
A => B
作为隐式转换器,不如将此转换行为封装在它自己的构造中。这将防止由非预期转换器候选者引入的不可预测性和错误。因此,您可以定义类似
OptionConverter
trait的东西,然后在代码中使用它implicitly
。