将类型类添加到Java枚举中 - 没有模拟

时间:2017-01-29 03:53:12

标签: java scala enums typeclass simulacrum

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

而不是简单的旧模式匹配并且将地图映射到另一个枚举类型,我认为编写类型类看起来更干净(也有点酷)。当我使用simulacrum来做这件事时,它编译并运行得非常好。但是,当我尝试自己手动编写类型类时,会抛出编译错误

[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的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 !!
  }
}

对错误消息的任何启发都非常感谢。

1 个答案:

答案 0 :(得分:1)

这是因为你的隐式类及其定义的对象都被称为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)
        ^

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

EmailEnumOps

隐式类EmailEnumOps被编译为类EmailEnumOps和隐式def EmailEnumOps._。因此,当您导入TradeEnum.CLEARED时,隐式def被对象遮蔽,因此@Component({ selector: 'my-app', template: ` <div> <h2>Hello {{name}}</h2> {{collaborators["0"]?.fullname}} </div> `, }) export class App { name:string; collaborators: [{fullname: string}]; constructor() { this.name = 'Angular2' this.collaborators = []; } } 无法隐式转换。

此行为符合language specification

中的规定
  

不同类型的绑定在其上定义了优先级:

     
      
  1. 本地,继承或制作的定义和声明   可以通过package子句获得,也可以在同一个编译中定义   单位作为参考,具有最高优先权。

  2.   
  3. 显式导入有   下一个最高优先级。

  4.   
  5. 通配符导入次之   优先。

  6.   
  7. 包子句提供的定义,但不是   也在与引用相同的编译单元中定义   最低优先级。

  8.