使用Precog配置模式的Scala蛋糕模式编译错误



根据这个问题,我现在有以下内容:

case class Pet(val name: String)
trait ConfigComponent {
  type Config
  def config: Config
}
trait VetModule extends ConfigComponent {
  type Config <: VetModuleConfig
  def vet: Vet
  trait Vet {
    def vaccinate(pet: Pet)
  }
  trait VetModuleConfig {
    def extra: String
  }
}
trait VetModuleImpl extends VetModule {
  override def vet: Vet = VetImpl
  object VetImpl extends Vet {
    def vaccinate(pet: Pet) = println("Vaccinate:" + pet + " " + config.extra)
  }
}
trait AnotherModule extends ConfigComponent {
  type Config <: AnotherConfig
  def getLastName(): String
  trait AnotherConfig {
    val lastName: String
  }
}
trait AnotherModuleImpl extends AnotherModule {
  override def getLastName(): String = config.lastName
}
trait PetStoreModule extends ConfigComponent {
  type Config <: PetStoreConfig
  def petStore: PetStore
  trait PetStore {
    def sell(pet: Pet): Unit
  }
  trait PetStoreConfig {
    val petStoreName: String
  }
}
trait PetStoreModuleImpl extends PetStoreModule {
  self: VetModule with AnotherModule =>
  override def petStore: PetStore = PetstoreImpl
  object PetstoreImpl extends PetStore {
    def sell(pet: Pet) {
      vet.vaccinate(pet)
      println(s"Sold $pet! [Store: ${config.petStoreName}, lastName: $getLastName]")
    }
  }
}
class MyApp extends PetStoreModuleImpl with VetModuleImpl with AnotherModuleImpl {
  type Config = PetStoreConfig with AnotherConfig
  override object config extends PetStoreConfig with AnotherConfig {
    val petStoreName = "MyPetStore"
    val lastName = "MyLastName"
  }
  petStore.sell(new Pet("Fido"))
}

object Main {
  def main(args: Array[String]) {
    new MyApp
  }
}

我得到以下编译错误:

value petStoreName is not a member of PetStoreModuleImpl.this.Config
     println(s"Sold $pet! [Store: ${config.petStoreName}, lastName: $getLastName]")
                                   ^

这实际上是我一直在努力克服的错误。有人能解释一下为什么会发生这种情况吗?目前,作为一种变通方法,我只是在每个模块实现中显式地转换配置对象。

您所写的应该有效,但由于这个错误而无效。

你可以使用许多变通方法。将type Config = PetStoreConfig with AnotherConfig添加到模块实现中可能比强制转换稍微不那么令人不快。

更新:正如som-snytt在评论和回答中所指出的,在self-type的末尾添加with PetStoreModuleImpl(关键不是with PetStoreModule,正如你所期望的)是一个更好的解决方案。

作为脚注:正如在对SI-7255的评论中所讨论的,依赖对象类型演算(它被设计为"Scala类型系统的新基础")将解决这个"Scala的类型系统中的基本问题"。

您可以争论自己的类型以保留您想要的抽象类型成员,因为最后一个绑定获胜:

trait PetStoreModuleImpl extends PetStoreModule {
  self: VetModule with AnotherModule with PetStoreModuleImpl =>
  override def petStore: PetStore = PetstoreImpl
  object PetstoreImpl extends PetStore {
    def sell(pet: Pet) {
      vet.vaccinate(pet)
      println(s"Sold $pet! [Store: ${config.petStoreName}, lastName: $getLastName]")
    }
  }
}

然后它会告诉你兽医模块没有配置:

class MyApp extends PetStoreModuleImpl with VetModuleImpl with AnotherModuleImpl {
  override type Config = PetStoreConfig with VetModuleConfig with AnotherConfig
  override object config extends PetStoreConfig with VetModuleConfig with AnotherConfig {
    val petStoreName = "MyPetStore"
    val lastName = "MyLastName"
    val extra = "vet-info"
  }
  petStore.sell(new Pet("Fido"))
}

最新更新