2016-05-19 2 views
0

Я ищу общий способ преобразования пар классов case с использованием implicits. Чтобы сделать это конкретным, я пишу новую конфигурационную библиотеку, которая должна поддерживать обратную совместимость с существующей библиотекой конфигурации. Чтобы сделать этот переход настолько безболезненным, насколько это возможно, я надеюсь использовать implicits, чтобы преобразовать новые классы case к их более старым коллегам по запросу.Scala: универсальное решение для неявного преобразования пар классов case

В приведенном ниже примере классы 1 находятся в старой библиотеке, а классы 2 - из новой библиотеки. Я использую apply на сопутствующих объектах для извлечения фактических данных из экземпляра Config (используя библиотеку Typesbox config).

package older { 
    case class A1(a: String) 
    case class B1(b: Int) 
} 

package newer { 
    case class A2(a: String) 
    case class B2(b: Int) 

    object A2 { 
    def apply(cfg: Config): A2 = A2(a = cfg.getString("a")) 
    def toOlder(a2: A2) = older.A1(a = a2.a) 
    } 

    object B2 { 
    def apply(cfg: Config): B2 = B2(b = cfg.getInt("b")) 
    def toOlder(b2: B2) = older.B1(b = b2.b) 
    } 
} 

В идеале, я бы не написать неявную функцию для преобразования каждого из классов случаев (A1 ->A2, B1 ->B2 и т.д.), но может использовать один общий неявный обрабатывать все их. Цель состоит в том, чтобы иметь возможность использовать экземпляр A2 для a1 метода ниже, просто импортируя неявный:

trait Foo { 
    def a1: older.A1 
} 

Я стучал головой о стену в течение нескольких часов в настоящее время и не может прийти с решением.

Заранее спасибо.

ответ

0

Естественно, после того, как я отошел от этой проблемы за пару часов я пришел с решением. Смутно, это тоже довольно просто.

package older { 
    case class A1(a: String) 
    case class B1(b: Int) 
} 

package newer { 

    sealed trait Convertable[A <: AnyRef, B <: AnyRef] { 
     implicit val formats = DefaultFormats 

     implicit def convert(new: A)(implicit mB: Manifest[B]): B = { 
      read[B](write(new)) 
     } 
    } 

    case class A2(a: String) 
    case class B2(b: Int) 

    object A2 extends Convertable[A2, older.A1] { 
     def apply(cfg: Config): A2 = A2(a = cfg.getString("a")) 
    } 

    object B2 extends Convertabe[B2, older.B1] { 
     def apply(cfg: Config): B2 = B2(b = cfg.getInt("b")) 
    } 
} 

отметить также, что я использовал возможность Lift-JSON, чтобы преобразовать классы случая к JSON и обратно для выполнения фактического экземпляра. Казалось легче, чем возиться с отражением.

Спасибо за помощь!

1

Решает ли ваша проблема или я что-то неправильно понял?

implicit final def aToOlder(self: A2): A1 = A1(a = self.a) 
implicit final def bToOlder(self: B2): B1 = B1(b = self.b) 

Использование:

val old: A1 = A1("John") 
val oldFromNew: A1 = A2("Doe") // This will be implicitly converted from the `A2` instance to the `A1` instance 
+0

Это будет работать, но я надеюсь избежать написания неявного для каждого класса case. Спасибо за ответ! – richid

Смежные вопросы