将类型类添加到Java枚举-无需模拟 [英] Adding a Typeclass to Java enum - without simulacrum

查看:133
本文介绍了将类型类添加到Java枚举-无需模拟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将几个Java枚举值转换为另一个Java枚举(在Scala枚举上使用Java枚举是由于遗留原因-枚举实际上是使用JAXB生成的)。

I am trying to convert a couple of Java enumerations values into another Java enumeration (the usage of Java enum over Scala Enumeration is due to legacy reasons - the enums are actually generated using JAXB).

我认为写一个类型类看起来更简洁(也很酷),而不是简单的旧模式匹配并没有将一种枚举类型映射到另一种枚举类型的映射。当我使用Simulacrum执行此操作时,它会编译并运行得很好。但是,当我尝试自己手工编码类型类时,会引发编译错误

Instead of a plain old pattern matching and having a map mapping one enumeration type to another, I figured writing a typeclass looks cleaner (also kinda cool). When I use simulacrum to do this, it compiles and runs just great. However, when I try to hand-code the typeclass myself, it throws a compilation error

[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枚举的代码为:

The code for the Java enumerations are :

源枚举

public enum TradeEnum {
    CONFIRMED, CLEARED
}

public enum SeriesEnum {
    CREATED,DELETED
}

目标枚举

public enum EmailEnum {
    T_CONFIRMED, T_CLEARED, S_CREATED, S_DELETED
}

使用Simulacrum的Typeclass(效果很好!)

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)
  }
}

手编码类型类(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 !!
  }
}

任何对错误消息的理解都受到高度赞赏。

Any light on the error message is highly appreciated.

推荐答案

这是因为您的隐式类及其定义的对象都称为 EmailEnumOps

It's because your implicit class and the object it's defined in are both called EmailEnumOps.

当您更改对象名称时,它起作用:

When you change the name of the object it works:

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 :-)
  }
}

当在当前作用域中定义一个对象,然后您导入一个具有相同名称的成员时,看起来第一个对象仍在遮蔽导入的成员。

It looks like that when an object is defined in the current scope and then you import a member with the same name, the first object is still shadowing the imported member.

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)
        ^

隐式类 EmailEnumOps 被编译为类 EmailEnumOps 和隐式def EmailEnumOps 。因此,当您导入 EmailEnumOps ._ 时,隐式def被对象遮盖了,因此 TradeEnum.CLEARED 不能

An implicit class EmailEnumOps is compiled into a class EmailEnumOps and an implicit def EmailEnumOps. So when you imported EmailEnumOps._ that implicit def was shadowed by the object, and consequently TradeEnum.CLEARED could not be implicitly converted.

此行为如语言规范


Bindings of different kinds have a precedence defined on them:


  1. 本地,继承或使
    可用的定义和声明由package子句定义,并且在与引用相同的编译
    单元中定义,具有最高优先级。

  1. 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.

package子句提供的定义(但未在与引用相同的编译单元中定义的
)具有最低优先级

Definitions made available by a package clause, but not also defined in the same compilation unit as the reference, have lowest precedence.


这篇关于将类型类添加到Java枚举-无需模拟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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