具有不同属性名称的 Scala 通用类型层次结构
scala generic type hierarchy with different attribute name
我使用 https://pureconfig.github.io/ 加载配置值。例如,对于数据库中的每个 table,我存储 (db: String, table: String)
。但是,我需要表示特定的 table。因此,每个人都有一个单独的特征。即:
trait Thing
trait ThingWithStuff extends Thing {
def value:String
}
trait FooThing extends Thing{
def fooThing: ThingWithStuff
}
trait BarThing extends Thing{
def barThing: ThingWithStuff
}
它们都具有不同的属性名称和相同的类型,return 中的类型相同,即 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 {
db = "a"
table = "b"
}
table-second {
db = "foo"
table = "baz"
}
前面不能有相同的标识符,否则它会覆盖每个值以仅保留此标识符的最后一项的值。因此,我求助于使用不同的属性名称(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)
结果:
I am a FooThing!
I am a BarThing!
基本上,我们 "create" 没有多态性 - 两个隐式 ThingEx
允许您将 fooThing
和 barThing
绑定在一起。您只需定义此绑定一次 - 然后您就可以在任何地方使用它。
如果 ad-hoc-polymorphism 和 type 类 对你来说是新的,你可以开始 here 例如。
希望对您有所帮助!
我使用 https://pureconfig.github.io/ 加载配置值。例如,对于数据库中的每个 table,我存储 (db: String, table: String)
。但是,我需要表示特定的 table。因此,每个人都有一个单独的特征。即:
trait Thing
trait ThingWithStuff extends Thing {
def value:String
}
trait FooThing extends Thing{
def fooThing: ThingWithStuff
}
trait BarThing extends Thing{
def barThing: ThingWithStuff
}
它们都具有不同的属性名称和相同的类型,return 中的类型相同,即 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 {
db = "a"
table = "b"
}
table-second {
db = "foo"
table = "baz"
}
前面不能有相同的标识符,否则它会覆盖每个值以仅保留此标识符的最后一项的值。因此,我求助于使用不同的属性名称(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)
结果:
I am a FooThing!
I am a BarThing!
基本上,我们 "create" 没有多态性 - 两个隐式 ThingEx
允许您将 fooThing
和 barThing
绑定在一起。您只需定义此绑定一次 - 然后您就可以在任何地方使用它。
如果 ad-hoc-polymorphism 和 type 类 对你来说是新的,你可以开始 here 例如。
希望对您有所帮助!