跨多个项目的Scala隐式和类型类

时间:2018-07-22 22:28:49

标签: scala implicit

亲爱的Scala开发人员,

上下文

我有两个Scala项目,分别为coreinfracore项目包含特征定义,而infra包含这些特征的具体实现。因此,infra取决于core

core项目中,我具有使用蛋糕模式的特征。

trait GetSectionsOfTypeComp {
  def sectionsOfType[SectionType <: SoftwareSection](implicit evidence: GetSectionsOfType[SectionType]): GetSectionsOfType[SectionType]

  trait GetSectionsOfType[SectionType <: SoftwareSection] {
    def getAll(dataStream: InputStream): Seq[SectionType]
  }
}

其中SoftwareSection是一个有一个孩子的特征:

sealed trait SoftwareSection {
  def name: String
  def rawAddress: SoftwareAddress
  def rawSize: Long
}

case class CodeSoftwareSection(name: String, rawAddress: SoftwareAddress, rawSize: Long) extends SoftwareSection

infra项目中,我想根据方法GetSectionsOfType.sectionsOfType的类型参数来分离逻辑。因此,我使用类型类:

trait PeParserGetSectionsOfCodeComp extends GetSectionsOfTypeComp {
  implicit val foo: GetSectionsOfType[CodeSoftwareSection] = GetSectionOfCode

  override def sectionsOfType[SectionType <: SoftwareSection](implicit evidence: GetSectionsOfType[SectionType]): GetSectionsOfType[SectionType] = evidence

  implicit object GetSectionOfCode extends GetSectionsOfType[CodeSoftwareSection] {
    override def getAll(dataStream: InputStream): Seq[CodeSoftwareSection] = Seq(CodeSoftwareSection("code", SoftwareAddress(0), 0))
  }
}

trait PeParserGetSectionsOfDataComp extends GetSectionsOfTypeComp {
  implicit val bar: GetSectionsOfType[DataSoftwareSection] = GetSectionOfData

  override def sectionsOfType[SectionType <: SoftwareSection](implicit evidence: GetSectionsOfType[SectionType]): GetSectionsOfType[SectionType] = evidence

  implicit object GetSectionOfData extends GetSectionsOfType[DataSoftwareSection] {
    override def getAll(dataStream: InputStream): Seq[DataSoftwareSection] = Seq(DataSoftwareSection("data", SoftwareAddress(0), 0))
  }
}

位于项目core中的我的业务逻辑需要调用sectionsOfType实例的方法GetSectionsOfType,该方法将使用蛋糕模式轻轻地注入。

解决隐式类型类的问题

由于项目coreinfra项目没有(也不应该具有!)依赖性,因此调用方法sectionsOfType[CodeSoftwareSection].getAll(openStream)会使编译器感到生气,因为它不能找到隐式参数的任何隐式值,这很正常!

现在,我不能只导入GetSectionsOfType的所有实现,因为它将在我的项目core中公开该实现。为了解决这种情况,我阅读了Scala文档中的文章WHERE DOES SCALA LOOK FOR IMPLICITS?,希望找到另一种方式来解决我的隐式问题,而又不会依赖于项目{{1} }。

不幸的是,我找不到任何方法来解决我的隐式问题,因为项目core无法链接项目infra,隐式参数必须在编译时解决。

是否有任何建议或替代方法来保持代码的清洁?

编辑3 :使用蛋糕模式重构代码。
编辑4 :在下面的项目core中向组件添加调用示例。

infra

1 个答案:

答案 0 :(得分:0)

关于您当前代码的一些观察结果:

在您的GetSectionsOfTypeComp中,您可以写作

trait GetSectionsOfTypeComp {
  def sectionsOfType[SectionType <: SoftwareSection](implicit evidence: GetSectionsOfType[SectionType]): GetSectionsOfType[SectionType] = evidence
}

如果您要做的就是在每个(或至少许多)实施中返回evidende。

此外,您不必为隐式对象创建implicit val

这绝对不是必须的,但是您可以避免为GetSectionsOfTypeComp创建子类型,同时将类型类代码分开。您最终会遇到这种情况:

import java.io.InputStream

// type class code
trait GetSectionsOfType[SectionType <: SoftwareSection] {
  def getAll(dataStream: InputStream): Seq[SectionType]
}

object GetSectionsOfType {
  implicit object GetSectionOfCode extends GetSectionsOfType[CodeSoftwareSection] {
    override def getAll(dataStream: InputStream): Seq[CodeSoftwareSection] = Seq(CodeSoftwareSection("code", SoftwareAddress(0), 0))
  }

  implicit object GetSectionOfData extends GetSectionsOfType[DataSoftwareSection] {
    override def getAll(dataStream: InputStream): Seq[DataSoftwareSection] = Seq(DataSoftwareSection("data", SoftwareAddress(0), 0))
  }
}

// component 
trait GetSectionsOfTypeComp {
  def sectionsOfType[SectionType <: SoftwareSection](implicit evidence: GetSectionsOfType[SectionType]): GetSectionsOfType[SectionType] = evidence
}

对于实际问题,我不知道您的所有代码,但您将核心项目定义为特征定义的地方。对于核心项目了解实现是个好主意吗?您是否不应该考虑将呼叫放在其他地方(例如新模块)?要确定有关呼叫站点的更多知识,就需要。

希望这会有所帮助。