scala具有不同属性名称的泛型类型层次结构

scala具有不同属性名称的泛型类型层次结构,scala,generics,type-level-computation,pureconfig,Scala,Generics,Type Level Computation,Pureconfig,我使用加载配置值。例如,对于数据库中的每个表,我存储(db:String,table:String)。但是,我需要表示特定的表。因此,每个人都有一个单独的特点。即: trait Thing trait ThingWithStuff extends Thing { def value:String } trait FooThing extends Thing{ def fooThing: ThingWithStuff } trait BarThing extends Thing

我使用加载配置值。例如,对于数据库中的每个表,我存储
(db:String,table:String)
。但是,我需要表示特定的表。因此,每个人都有一个单独的特点。即:

trait Thing
trait ThingWithStuff extends Thing {
    def value:String
}

trait FooThing extends Thing{
    def fooThing: ThingWithStuff
}

trait BarThing extends Thing{
    def barThing: ThingWithStuff
}
它们都具有相同类型的不同属性名称,作为回报,这些属性名称保持不变,即
db
table
。使用某些方法处理这些问题时:

def myMethodFoo(thing:FooThing)= println(thing.fooThing)
def myMethodBar(thing:BarThing)= println(thing.barThing)
这会导致代码重复。尝试使用泛型修复这些问题时,我无法编写如下函数:

def myMethod[T<: Thing] = println(thing.thing)
不能预先具有相同的标识符,否则会覆盖每个值,从而仅保留该标识符最后一项的值。因此,我求助于使用不同的属性名称(
table-first,table-second
,或者特别是在示例中:
fooThing,barThing


如何解决此问题以防止代码重复?

下面是一个使用类型类的解决方案,用于
FooThing
BarThing

trait Thing

trait ThingWithStuff {
    def value: String
}

trait FooThing extends Thing {
    def fooThing: ThingWithStuff
}

trait BarThing extends Thing {
    def barThing: ThingWithStuff
}

// Define implicits:

trait ThingEx[SomeThing <: Thing] {
  def extract(thing: SomeThing): ThingWithStuff
}

implicit val fooThingEx = new ThingEx[FooThing]{
  def extract(thing: FooThing): ThingWithStuff = thing.fooThing
}

implicit val barThingEx = new ThingEx[BarThing]{
  def extract(thing: BarThing): ThingWithStuff = thing.barThing
}

// Define the method:

def myMethod[SomeThing <: Thing](thing: SomeThing)(implicit thingEx: ThingEx[SomeThing]) =
  println(thingEx.extract(thing).value)

// Try it out:

val foo = new FooThing {
  def fooThing = new ThingWithStuff {
    def value = "I am a FooThing!"
  }
}


val bar = new BarThing {
  def barThing = new ThingWithStuff {
    def value = "I am a BarThing!"
  }
}

myMethod(foo)

myMethod(bar)

基本上,我们在没有多态性的地方“创建”多态性-两个隐式
ThingEx
允许您将
fooThing
barThing
绑定在一起。您只需定义此绑定一次,然后就可以在任何地方使用它

如果特别多态性和类型类对您来说是新的,例如,您可以开始


我希望这有帮助

我想,
FooThing
BarThing
扩展了
东西
?确实应该像这样很棒。有可能自动生成一个封闭特征的抽取器吗?@GeorgHeiler你可以使用Shapeless,或者类似的东西?但我不确定。而且,如果我不仅想读取(提取器),而且还想创建对象,这将如何工作?有动态喷油器吗?@GeorgHeiler这里没有“动态”的东西。所有内容都是静态类型的,因此类型安全。看看不成形的H列表,它们可能就是你想要的。否则,您总是可以在
ThingEx
-typeclass上添加另一个函数,类似于
def create(thing:ThingWithStuff):FooThing=newfoothing{…thing…}
def create(thing:ThingWithStuff):BarThing=new BarThingThing{…thing…}
中的
,分别地
trait Thing

trait ThingWithStuff {
    def value: String
}

trait FooThing extends Thing {
    def fooThing: ThingWithStuff
}

trait BarThing extends Thing {
    def barThing: ThingWithStuff
}

// Define implicits:

trait ThingEx[SomeThing <: Thing] {
  def extract(thing: SomeThing): ThingWithStuff
}

implicit val fooThingEx = new ThingEx[FooThing]{
  def extract(thing: FooThing): ThingWithStuff = thing.fooThing
}

implicit val barThingEx = new ThingEx[BarThing]{
  def extract(thing: BarThing): ThingWithStuff = thing.barThing
}

// Define the method:

def myMethod[SomeThing <: Thing](thing: SomeThing)(implicit thingEx: ThingEx[SomeThing]) =
  println(thingEx.extract(thing).value)

// Try it out:

val foo = new FooThing {
  def fooThing = new ThingWithStuff {
    def value = "I am a FooThing!"
  }
}


val bar = new BarThing {
  def barThing = new ThingWithStuff {
    def value = "I am a BarThing!"
  }
}

myMethod(foo)

myMethod(bar)
I am a FooThing!
I am a BarThing!