4

Following from this question, I have now the following:

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

I get the following compile error:

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

This is actually the error I have been struggling with. Can somebody explain why it occurs? Currently, as a work-around, I just explicitly cast the config object in each module implementation.

4

2 回答 2

6

您所写的内容应该可以工作,但由于此错误而无法正常工作。

您可以使用多种解决方法。添加type Config = PetStoreConfig with AnotherConfig到您的模块实现中可能比强制转换要少一些不愉快。

更新:正如 som-snytt 在评论和答案中指出的那样,在 self 类型的末尾添加with PetStoreModuleImpl(至关重要的是with PetStoreModule,如您所料)是一个更好的解决方案。

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

于 2013-08-20T10:35:45.063 回答
3

您可以调整您的自我类型以保留您想要的抽象类型成员,因为最后一个绑定获胜

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

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

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"))
}
于 2013-08-20T14:43:09.453 回答