具有不同属性名称的Scala通用类型层次结构 [英] scala generic type hierarchy with different attribute name
问题描述
我使用 https://pureconfig.github.io/来加载配置值.例如,对于数据库中的每个表,我都存储(db: String, table: String)
.但是,我需要表示特定的表.因此,每个人都有各自的特质.即:
I use https://pureconfig.github.io/ to load configuration values. For example for each table in a database, I store (db: String, table: String)
.However, I need to denote specific tables. Therefore, each one has a separate trait. I.e.:
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
.使用某些方法处理这些文件时:
They all have a different attribute name with the same type which in return holds i.e. db
and table
. When processing these with some methods:
def myMethodFoo(thing:FooThing)= println(thing.fooThing)
def myMethodBar(thing:BarThing)= println(thing.barThing)
它导致代码重复.试图使用泛型修复这些问题,我无法编写类似这样的函数:
it leads to code duplication. Trying to fix these using generics I am not able to write a function like:
def myMethod[T<: Thing] = println(thing.thing)
,因为属性名称会有所不同. 有没有解决的聪明方法? 注意:
as the attribute name would be different. Is there a smart way around it? Note:
table-first {
db = "a"
table = "b"
}
table-second {
db = "foo"
table = "baz"
}
不能在前面具有相同的标识符,否则它将覆盖每个值以仅保留该标识符的最后一项的值.因此,我求助于使用不同的属性名称(table-first, table-second
或专门用于示例:fooThing, barThing
)
cannot have the same identifier up front as otherwise it would overwrite each value to hold only the value of the last item for this identifier. Therefore, I resorted to use different attribute names (table-first, table-second
or specifically for the example: fooThing, barThing
)
如何解决此问题以防止代码重复?
How can I fix this issue to prevent code duplication?
推荐答案
以下是对FooThing
和BarThing
使用类型类的解决方案:
Here is a solution using type classes for FooThing
and 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!
基本上,我们在没有任何差异的情况下创建"多态性-两个隐式ThingEx
允许您将fooThing
和barThing
绑定在一起.您只需定义一次此绑定-然后就可以在任何地方使用它.
Basically, we "create" polymorphism where there isn't any - the two implicit ThingEx
allow you to bind fooThing
and barThing
together. You only have to define this bind once - and then you can use it everywhere.
如果您是 ad-hoc-polymorphism 和 type类的新手,则可以开始
If ad-hoc-polymorphism and type classes are new to you, you can start here for example.
我希望这会有所帮助!
这篇关于具有不同属性名称的Scala通用类型层次结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!