将类型类添加到 Java 枚举 - 没有模拟
Adding a Typeclass to Java enum - without simulacrum
我正在尝试将几个 Java 枚举值转换为另一个 Java 枚举(在 Scala 枚举上使用 Java 枚举是由于遗留原因 - 枚举是实际上是使用 JAXB 生成的)。
我认为编写一个类型 class 看起来更干净(也有点酷),而不是普通的旧模式匹配和映射将一种枚举类型映射到另一种。当我使用 simulacrum 执行此操作时,它编译并运行得很好。但是,当我尝试自己手动编写类型 class 时,它会引发编译错误
[error] /Users/arun/IdeaProjects/AdvancedScala/src/main/scala/MultipleToSingleEnum.scala:32: value toEmail is not a member of TradeEnum
[error] println (TradeEnum.CLEARED.toEmail)
Java 枚举的代码是:
源枚举
public enum TradeEnum {
CONFIRMED, CLEARED
}
public enum SeriesEnum {
CREATED,DELETED
}
目标枚举
public enum EmailEnum {
T_CONFIRMED, T_CLEARED, S_CREATED, S_DELETED
}
使用 Simulacrum 输入class(效果很好!)
import simulacrum._
@typeclass trait EmailEnumConvertibleSim[A]{
def toEmailEnum(value:A):Option[EmailEnum]
}
object EmailEnumConvertibleSim{
implicit val tradeToEmailEnum = new EmailEnumConvertibleSim[TradeEnum]{
private val map=Map(
TradeEnum.CLEARED -> EmailEnum.T_CLEARED,
TradeEnum.CONFIRMED -> EmailEnum.T_CONFIRMED
)
override def toEmailEnum(value: TradeEnum): Option[EmailEnum] = map.get(value)
}
implicit val seriesToEmailEnum = new EmailEnumConvertibleSim[SeriesEnum]{
private val map=Map(
SeriesEnum.CREATED -> EmailEnum.S_CREATED,
SeriesEnum.DELETED -> EmailEnum.S_DELETED
)
override def toEmailEnum(value: SeriesEnum): Option[EmailEnum] = map.get(value)
}
}
import EmailEnumConvertibleSim.ops._
object MultipleToSingleEnumSim {
def main(args: Array[String]): Unit = {
println (TradeEnum.CLEARED.toEmailEnum)
}
}
手写类型class (Ops)
trait EmailEnumConvertible[A]{
def toEmailEnum(value:A):Option[EmailEnum]
}
object EmailEnumConvertible{
implicit val tradeToEmailEnum = new EmailEnumConvertible[TradeEnum]{
private val map=Map(
TradeEnum.CLEARED -> EmailEnum.T_CLEARED,
TradeEnum.CONFIRMED -> EmailEnum.T_CONFIRMED
)
override def toEmailEnum(value: TradeEnum): Option[EmailEnum] = map.get(value)
}
}
object EmailEnumOps{
implicit class EmailEnumOps[A] (value:A){
def toEmail()(implicit emailConvertable:EmailEnumConvertible[A]):Option[EmailEnum]={
emailConvertable.toEmailEnum(value)
}
}
}
import EmailEnumOps._
object MultipleToSingleEnum {
def main(args: Array[String]): Unit = {
println (TradeEnum.CLEARED.toEmail) //ERROR IS REPORTED HERE !!
}
}
非常感谢任何关于错误消息的说明。
因为你的隐式class和它定义的对象都叫EmailEnumOps
.
当您更改对象的名称时,它会起作用:
trait EmailEnumConvertible[A]{
def toEmailEnum(value: A): Option[EmailEnum]
}
object EmailEnumConvertible{
implicit val tradeToEmailEnum: EmailEnumConvertible[TradeEnum] = new EmailEnumConvertible[TradeEnum]{
private val map = Map(
TradeEnum.CLEARED -> EmailEnum.T_CLEARED,
TradeEnum.CONFIRMED -> EmailEnum.T_CONFIRMED
)
override def toEmailEnum(value: TradeEnum): Option[EmailEnum] = map.get(value)
}
}
object AnyOtherName{
implicit class EmailEnumOps[A] (value: A){
def toEmail()(implicit emailConvertable:EmailEnumConvertible[A]): Option[EmailEnum]={
emailConvertable.toEmailEnum(value)
}
}
}
import AnyOtherName._
object MultipleToSingleEnum {
def main(args: Array[String]): Unit = {
println (TradeEnum.CLEARED.toEmail) // No error :-)
}
}
看起来当在当前作用域中定义了一个对象,然后您导入一个同名成员时,第一个对象仍然隐藏导入的成员。
scala> :paste
// Entering paste mode (ctrl-D to finish)
object A { def B(a: Int) = "foo" }
object B
import A._
B(4)
// Exiting paste mode, now interpreting.
<pastie>:41: error: B.type does not take parameters
B(4)
^
隐式 class EmailEnumOps
被编译成 class EmailEnumOps
和隐式 def EmailEnumOps
。因此,当您导入 EmailEnumOps._
时,隐式 def 被对象隐藏,因此 TradeEnum.CLEARED
无法隐式转换。
此行为在 language specification 中指定:
Bindings of different kinds have a precedence defined on them:
Definitions and declarations that are local, inherited, or made
available by a package clause and also defined in the same compilation
unit as the reference, have highest precedence.
Explicit imports have
next highest precedence.
Wildcard imports have next highest
precedence.
Definitions made available by a package clause, but not
also defined in the same compilation unit as the reference, have
lowest precedence.
我正在尝试将几个 Java 枚举值转换为另一个 Java 枚举(在 Scala 枚举上使用 Java 枚举是由于遗留原因 - 枚举是实际上是使用 JAXB 生成的)。
我认为编写一个类型 class 看起来更干净(也有点酷),而不是普通的旧模式匹配和映射将一种枚举类型映射到另一种。当我使用 simulacrum 执行此操作时,它编译并运行得很好。但是,当我尝试自己手动编写类型 class 时,它会引发编译错误
[error] /Users/arun/IdeaProjects/AdvancedScala/src/main/scala/MultipleToSingleEnum.scala:32: value toEmail is not a member of TradeEnum
[error] println (TradeEnum.CLEARED.toEmail)
Java 枚举的代码是:
源枚举
public enum TradeEnum {
CONFIRMED, CLEARED
}
public enum SeriesEnum {
CREATED,DELETED
}
目标枚举
public enum EmailEnum {
T_CONFIRMED, T_CLEARED, S_CREATED, S_DELETED
}
使用 Simulacrum 输入class(效果很好!)
import simulacrum._
@typeclass trait EmailEnumConvertibleSim[A]{
def toEmailEnum(value:A):Option[EmailEnum]
}
object EmailEnumConvertibleSim{
implicit val tradeToEmailEnum = new EmailEnumConvertibleSim[TradeEnum]{
private val map=Map(
TradeEnum.CLEARED -> EmailEnum.T_CLEARED,
TradeEnum.CONFIRMED -> EmailEnum.T_CONFIRMED
)
override def toEmailEnum(value: TradeEnum): Option[EmailEnum] = map.get(value)
}
implicit val seriesToEmailEnum = new EmailEnumConvertibleSim[SeriesEnum]{
private val map=Map(
SeriesEnum.CREATED -> EmailEnum.S_CREATED,
SeriesEnum.DELETED -> EmailEnum.S_DELETED
)
override def toEmailEnum(value: SeriesEnum): Option[EmailEnum] = map.get(value)
}
}
import EmailEnumConvertibleSim.ops._
object MultipleToSingleEnumSim {
def main(args: Array[String]): Unit = {
println (TradeEnum.CLEARED.toEmailEnum)
}
}
手写类型class (Ops)
trait EmailEnumConvertible[A]{
def toEmailEnum(value:A):Option[EmailEnum]
}
object EmailEnumConvertible{
implicit val tradeToEmailEnum = new EmailEnumConvertible[TradeEnum]{
private val map=Map(
TradeEnum.CLEARED -> EmailEnum.T_CLEARED,
TradeEnum.CONFIRMED -> EmailEnum.T_CONFIRMED
)
override def toEmailEnum(value: TradeEnum): Option[EmailEnum] = map.get(value)
}
}
object EmailEnumOps{
implicit class EmailEnumOps[A] (value:A){
def toEmail()(implicit emailConvertable:EmailEnumConvertible[A]):Option[EmailEnum]={
emailConvertable.toEmailEnum(value)
}
}
}
import EmailEnumOps._
object MultipleToSingleEnum {
def main(args: Array[String]): Unit = {
println (TradeEnum.CLEARED.toEmail) //ERROR IS REPORTED HERE !!
}
}
非常感谢任何关于错误消息的说明。
因为你的隐式class和它定义的对象都叫EmailEnumOps
.
当您更改对象的名称时,它会起作用:
trait EmailEnumConvertible[A]{
def toEmailEnum(value: A): Option[EmailEnum]
}
object EmailEnumConvertible{
implicit val tradeToEmailEnum: EmailEnumConvertible[TradeEnum] = new EmailEnumConvertible[TradeEnum]{
private val map = Map(
TradeEnum.CLEARED -> EmailEnum.T_CLEARED,
TradeEnum.CONFIRMED -> EmailEnum.T_CONFIRMED
)
override def toEmailEnum(value: TradeEnum): Option[EmailEnum] = map.get(value)
}
}
object AnyOtherName{
implicit class EmailEnumOps[A] (value: A){
def toEmail()(implicit emailConvertable:EmailEnumConvertible[A]): Option[EmailEnum]={
emailConvertable.toEmailEnum(value)
}
}
}
import AnyOtherName._
object MultipleToSingleEnum {
def main(args: Array[String]): Unit = {
println (TradeEnum.CLEARED.toEmail) // No error :-)
}
}
看起来当在当前作用域中定义了一个对象,然后您导入一个同名成员时,第一个对象仍然隐藏导入的成员。
scala> :paste
// Entering paste mode (ctrl-D to finish)
object A { def B(a: Int) = "foo" }
object B
import A._
B(4)
// Exiting paste mode, now interpreting.
<pastie>:41: error: B.type does not take parameters
B(4)
^
隐式 class EmailEnumOps
被编译成 class EmailEnumOps
和隐式 def EmailEnumOps
。因此,当您导入 EmailEnumOps._
时,隐式 def 被对象隐藏,因此 TradeEnum.CLEARED
无法隐式转换。
此行为在 language specification 中指定:
Bindings of different kinds have a precedence defined on them:
Definitions and declarations that are local, inherited, or made available by a package clause and also defined in the same compilation unit as the reference, have highest precedence.
Explicit imports have next highest precedence.
Wildcard imports have next highest precedence.
Definitions made available by a package clause, but not also defined in the same compilation unit as the reference, have lowest precedence.