[英]Get case class parameter types as a HList
I'm trying to generate instances of case class using shapeless我正在尝试使用无形生成案例 class 的实例
This works for generating instances of Foo
这适用于生成
Foo
的实例
case class Foo(x: Int, y: String)
class Context {
val random = new Random()
}
def genInt(context: Context): Int = {
context.random.nextInt()
}
def genString(context: Context): String = {
context.random.nextString(16)
}
object ClassesToGenerators extends Poly1 {
implicit def caseInt = at[Class[Int]](_ => genInt(_))
implicit def caseString = at[Class[String]](_ => genString(_))
}
val gen = Generic[Foo]
val context = new Context()
val classes = classOf[Int] :: classOf[String] :: HNil // can't figure out how to get this hlist programmatically
val generators = classes.map(ClassesToGenerators)
gen.from(generators.zipApply(generators.mapConst(context)))
However, I'm aiming to write something reusable like但是,我的目标是写一些可重用的东西,比如
def newInstance[T] -> T:
???
which could generate instances of any case classes that takes only int and string parameters.它可以生成仅采用 int 和 string 参数的任何案例类的实例。
As mentioned in the code snippet, I'm stuck at getting a hlist of case class attribute types ie would like to convert case class Foo(x: Int, y: String)
to classOf[Int]:: classOf[String]:: HNil
.正如代码片段中提到的,我一直在获取 case class 属性类型的列表,即想将
case class Foo(x: Int, y: String)
转换为classOf[Int]:: classOf[String]:: HNil
。 Any other approaches to this problem are also very appreciated but I'm not looking for a generic way of generating random instances of cases classes (as my use-case is different and used random generator just as an example)对此问题的任何其他方法也非常感谢,但我不是在寻找生成案例类随机实例的通用方法(因为我的用例不同,并且仅使用随机生成器作为示例)
IMHO, Shapeless is better used when you forget about all the fancy stuff and just focus on simple typeclass derivation using HList
like this:恕我直言,当您忘记所有花哨的东西并只关注使用
HList
的简单类型类派生时, Shapeless会更好地使用,如下所示:
import shapeless.{Generic, HList, HNil, :: => :!:}
import scala.util.Random
trait Context {
def random: Random
}
object Context {
object implicits {
implicit final val global: Context = new Context {
override final val random: Random = new Random()
}
}
}
trait Generator[A] {
def generate(context: Context): A
}
object Generator {
final def apply[A](implicit ev: Generator[A]): ev.type = ev
final def generate[A](implicit ev: Generator[A], ctx: Context): A =
ev.generate(ctx)
implicit final val IntGenerator: Generator[Int] =
new Generator[Int] {
override def generate(context: Context): Int =
context.random.nextInt()
}
implicit final val StringGenerator: Generator[String] =
new Generator[String] {
override def generate(context: Context): String =
context.random.nextString(16)
}
implicit final def auto[P <: Product](implicit ev: GeneratorGen[P]): Generator[P] = ev
}
sealed trait GeneratorRepr[R <: HList] extends Generator[R]
object GeneratorRepr {
implicit final val HNilGeneratorRepr: GeneratorRepr[HNil] =
new GeneratorRepr[HNil] {
override def generate(context: Context): HNil =
HNil
}
implicit final def HConsGeneratorRepr[E, T <: HList](
implicit ev: Generator[E], tail: GeneratorRepr[T]
): GeneratorRepr[E :!: T] =
new GeneratorRepr[E :!: T] {
override def generate(context: Context): E :!: T =
ev.generate(context) :: tail.generate(context)
}
}
sealed trait GeneratorGen[P <: Product] extends Generator[P]
object GeneratorGen {
implicit final def instance[P <: Product, R <: HList](
implicit gen: Generic.Aux[P, R], ev: GeneratorRepr[R]
): GeneratorGen[P] = new GeneratorGen[P] {
override def generate(context: Context): P =
gen.from(ev.generate(context))
}
}
Which can be used like this:可以这样使用:
import Context.implicits.global
final case class Foo(x: Int, y: String)
val result = Generator.generate[Foo]
// result: Foo = Foo(-2127375055, "鞰Ϗƨ沺㗝䚮Ⴍ욏ꖱꬮӝ闉믃雦峷")
Using built-in Shapeless type classes you can do使用内置的无形类型类,您可以做到
import shapeless.ops.hlist.FillWith
import shapeless.{Generic, HList, Poly0}
val context = new Context()
object ClassesToGenerators extends Poly0 {
implicit val caseInt = at[Int](genInt(context))
implicit val caseString = at[String](genString(context))
}
def newInstance[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[L <: HList]()(implicit
generic: Generic.Aux[A, L],
fillWith: FillWith[ClassesToGenerators.type, L]
): A = generic.from(fillWith())
}
newInstance[Foo]() // Foo(2018031886,⮐掐禃惌ᰧ佨妞ዤࠒ훿柲籐妭蝱⻤)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.