将数据从运行时存储转换为案例 class
Transforming data from a runtime storage to a case class
我正在尝试对 android.os.Bundle
API 进行抽象,旨在以这种方式生成捆绑包:
case class MyClass( a: Int, b: String )
val mc = MyClass( 3, "5" )
implicit val bundleable = Bundle.from[MyClass]()
val bundle = bundleable.write( mc )
assert( mc == bundleable.read( bundle ) )
将大小写 class 转换为 LabelledGeneric
并将键值对写入 Bundle
非常简单。但是我找不到将 Bundle
中的值提取回其原始类型的方法。我想那里的众多 JSON-库已经解决了这个问题,但我仍然找不到关于如何继续的线索。
object Bundle {
def from[T] = new {
def apply[LG <: HList, K <: HList, N <: Nat]()(
implicit
lg: LabelledGeneric.Aux[T, LG],
l: Length.Aux[LG, N],
k: Keys.Aux[LG, K],
lfw: LeftFolder.Aux[LG, Bundle, fold.write.type, Bundle],
//lfr: LeftFolder.Aux[K, Bundle, fold.read.type, LG],
ti: ToInt[N]
) = new Bundleable[T] {
override def write( value: T ): Bundle = {
lg.to( value ).foldLeft( new Bundle( toInt[N] ) )( fold.write )
}
override def read( bundle: Bundle ): T = ???
}
}
object fold {
object write extends Poly2 {
implicit def default[K <: Symbol, V: Bundleize]( implicit key: Witness.Aux[K] ): Case.Aux[Bundle, FieldType[K, V], Bundle] = {
at { ( bundle, value ) ⇒
implicitly[Bundleize[V]].write( key.value.name, value, bundle )
bundle
}
}
}
object read extends Poly2 {
???
}
}
}
/**
* Read or write a single value from/into a Bundle
*/
trait Bundleize[T] {
def read( key: String, bundle: Bundle ): T
def write( key: String, value: T, bundle: Bundle ): Unit
}
/**
* Transformation T <> Bundle
*/
trait Bundleable[T] {
def read( bundle: Bundle ): T
def write( value: T ): Bundle
}
此外,有没有一种方法可以重组代码,使我可以编写 Bundle.from[MyClass]
,而不是 Bundle.from[MyClass]()
(省略括号)?
多亏了指向无形 S 表达式示例的指针,我才能够组合出一个可行的解决方案。
import android.os.Bundle
import shapeless.labelled._
import shapeless.ops.hlist.{ Length, LeftFolder }
import shapeless._
import shapeless.Nat.toInt
import shapeless.ops.nat.ToInt
import shapeless.syntax.std.tuple._
/**
* Type class that instructs how to deserialize/serialize a value from/to a Bundle
*/
trait Bundleable[T] {
def read( bundle: Bundle ): T
def write( value: T ): Bundle
}
object Bundleable {
def apply[T]( r: Bundle ⇒ T, w: T ⇒ Bundle ) = new Bundleable[T] {
override def read( bundle: Bundle ) = r( bundle )
override def write( value: T ) = w( value )
}
def from[T: Bundleable]: Bundleable[T] = the[Bundleable[T]]
private object fold {
object write extends Poly2 {
implicit def default[K <: Symbol, V: Bundleize]( implicit key: Witness.Aux[K] ) = {
at[Bundle, FieldType[K, V]] { ( bundle, value ) ⇒
implicitly[Bundleize[V]].write( key.value.name, value, bundle )
bundle
}
}
}
}
implicit val `Bundleable[HNil]` = Bundleable[HNil]( _ ⇒ HNil, _ ⇒ Bundle.EMPTY )
implicit def `Bundleable[HList]`[K <: Symbol, V, T <: HList, N <: Nat](
implicit
key: Witness.Aux[K],
bv: Bundleize[V],
bt: Bundleable[T],
l: Length.Aux[FieldType[K, V] :: T, N],
ti: ToInt[N],
lf: LeftFolder.Aux[FieldType[K, V] :: T, Bundle, fold.write.type, Bundle]
) = Bundleable[FieldType[K, V] :: T](
bundle ⇒ field[K]( bv.read( key.value.name, bundle ) ) :: bt.read( bundle ),
_.foldLeft( new Bundle( toInt[N] ) )( fold.write )
)
implicit def `Bundleable[LabelledGeneric]`[T, LG](
implicit
lg: LabelledGeneric.Aux[T, LG],
b: Bundleable[LG]
) = Bundleable[T]( bundle ⇒ lg.from( b.read( bundle ) ), value ⇒ b.write( lg.to( value ) ) )
}
示例用法:
case class MyCaseClass( a: String, b: Int, c: Double )
val instance = MyCaseClass( "3", 3, 3 )
val bundleable = Bundleable.from[MyCaseClass]
val bundle: Bundle = bundleable.write( instance )
val deserialized = bundleable.read( bundle )
assert( instance == deserialized )
我正在尝试对 android.os.Bundle
API 进行抽象,旨在以这种方式生成捆绑包:
case class MyClass( a: Int, b: String )
val mc = MyClass( 3, "5" )
implicit val bundleable = Bundle.from[MyClass]()
val bundle = bundleable.write( mc )
assert( mc == bundleable.read( bundle ) )
将大小写 class 转换为 LabelledGeneric
并将键值对写入 Bundle
非常简单。但是我找不到将 Bundle
中的值提取回其原始类型的方法。我想那里的众多 JSON-库已经解决了这个问题,但我仍然找不到关于如何继续的线索。
object Bundle {
def from[T] = new {
def apply[LG <: HList, K <: HList, N <: Nat]()(
implicit
lg: LabelledGeneric.Aux[T, LG],
l: Length.Aux[LG, N],
k: Keys.Aux[LG, K],
lfw: LeftFolder.Aux[LG, Bundle, fold.write.type, Bundle],
//lfr: LeftFolder.Aux[K, Bundle, fold.read.type, LG],
ti: ToInt[N]
) = new Bundleable[T] {
override def write( value: T ): Bundle = {
lg.to( value ).foldLeft( new Bundle( toInt[N] ) )( fold.write )
}
override def read( bundle: Bundle ): T = ???
}
}
object fold {
object write extends Poly2 {
implicit def default[K <: Symbol, V: Bundleize]( implicit key: Witness.Aux[K] ): Case.Aux[Bundle, FieldType[K, V], Bundle] = {
at { ( bundle, value ) ⇒
implicitly[Bundleize[V]].write( key.value.name, value, bundle )
bundle
}
}
}
object read extends Poly2 {
???
}
}
}
/**
* Read or write a single value from/into a Bundle
*/
trait Bundleize[T] {
def read( key: String, bundle: Bundle ): T
def write( key: String, value: T, bundle: Bundle ): Unit
}
/**
* Transformation T <> Bundle
*/
trait Bundleable[T] {
def read( bundle: Bundle ): T
def write( value: T ): Bundle
}
此外,有没有一种方法可以重组代码,使我可以编写 Bundle.from[MyClass]
,而不是 Bundle.from[MyClass]()
(省略括号)?
多亏了指向无形 S 表达式示例的指针,我才能够组合出一个可行的解决方案。
import android.os.Bundle
import shapeless.labelled._
import shapeless.ops.hlist.{ Length, LeftFolder }
import shapeless._
import shapeless.Nat.toInt
import shapeless.ops.nat.ToInt
import shapeless.syntax.std.tuple._
/**
* Type class that instructs how to deserialize/serialize a value from/to a Bundle
*/
trait Bundleable[T] {
def read( bundle: Bundle ): T
def write( value: T ): Bundle
}
object Bundleable {
def apply[T]( r: Bundle ⇒ T, w: T ⇒ Bundle ) = new Bundleable[T] {
override def read( bundle: Bundle ) = r( bundle )
override def write( value: T ) = w( value )
}
def from[T: Bundleable]: Bundleable[T] = the[Bundleable[T]]
private object fold {
object write extends Poly2 {
implicit def default[K <: Symbol, V: Bundleize]( implicit key: Witness.Aux[K] ) = {
at[Bundle, FieldType[K, V]] { ( bundle, value ) ⇒
implicitly[Bundleize[V]].write( key.value.name, value, bundle )
bundle
}
}
}
}
implicit val `Bundleable[HNil]` = Bundleable[HNil]( _ ⇒ HNil, _ ⇒ Bundle.EMPTY )
implicit def `Bundleable[HList]`[K <: Symbol, V, T <: HList, N <: Nat](
implicit
key: Witness.Aux[K],
bv: Bundleize[V],
bt: Bundleable[T],
l: Length.Aux[FieldType[K, V] :: T, N],
ti: ToInt[N],
lf: LeftFolder.Aux[FieldType[K, V] :: T, Bundle, fold.write.type, Bundle]
) = Bundleable[FieldType[K, V] :: T](
bundle ⇒ field[K]( bv.read( key.value.name, bundle ) ) :: bt.read( bundle ),
_.foldLeft( new Bundle( toInt[N] ) )( fold.write )
)
implicit def `Bundleable[LabelledGeneric]`[T, LG](
implicit
lg: LabelledGeneric.Aux[T, LG],
b: Bundleable[LG]
) = Bundleable[T]( bundle ⇒ lg.from( b.read( bundle ) ), value ⇒ b.write( lg.to( value ) ) )
}
示例用法:
case class MyCaseClass( a: String, b: Int, c: Double )
val instance = MyCaseClass( "3", 3, 3 )
val bundleable = Bundleable.from[MyCaseClass]
val bundle: Bundle = bundleable.write( instance )
val deserialized = bundleable.read( bundle )
assert( instance == deserialized )