иерархия универсальных типов scala с другим именем атрибута - PullRequest
0 голосов
/ 10 декабря 2018

Я использую https://pureconfig.github.io/ для загрузки значений конфигурации.Например, для каждой таблицы в базе данных я храню (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 {
db = "a"
table = "b"
}
table-second {
db = "foo"
table = "baz"
}

не может иметь один и тот же идентификатор заранее, так как в противном случае будет перезаписано каждое значение, чтобы оно содержало только значение последнего элемента для этого идентификатора.Поэтому я прибегнул к использованию разных имен атрибутов (table-first, table-second или специально для примера: fooThing, barThing)

Как я могу исправить эту проблему, чтобы предотвратить дублирование кода?

1 Ответ

0 голосов
/ 10 декабря 2018

Вот решение, использующее классы типов для 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!

Попробуйте!

По сути, мы «создаем» полиморфизм там, где его нет - два неявных ThingEx позволяют вам связывать fooThing и barThing вместе.Вы должны определить эту привязку только один раз - и тогда вы сможете использовать ее везде.

Если ad-hoc-polymorphism и классов типов являются новыми для вас, вынапример, можно начать здесь .

Надеюсь, это поможет!

...