如何通过使用符号或类型对象将内容传递给泛型类型的函数?

huangapple go评论116阅读模式
英文:

How to pass into generic type using a Symbol or Type object into a generic typed function?

问题

在Scala中,是否可以将从Symbol或Type对象派生的类型传递给一个泛型函数?例如:

  1. case class Address(street: String, city: String, state: String, zipCode: String)
  2. case class Person(name: String, age: Int, address: Address)
  3. def a[T: TypeTag](): Unit = {
  4. val fields: Seq[Symbol] = typeOf[T].members.filter(_.isMethod == false).toSeq
  5. fields.foreach(x => {
  6. b[x.getMyType]() // 如何将字段的"Type"传递给泛型类型的函数?
  7. })
  8. }
  9. def b[T](): Unit = ???
  10. a[Person]()

从上面的示例中,我希望在调用a[Person]()时,在a()内部使用反射获取Person中的字段,然后使用每个字段的类型调用b[?]()

英文:

In Scala, is it possible to pass a type derived from a Symbol or Type object into a generic typed function? For example:

  1. case class Address(street: String, city: String, state: String, zipCode: String)
  2. case class Person(name: String, age: Int, address: Address)
  3. def a[T: TypeTag](): Unit = {
  4. val fields: Seq[Symbol] = typeOf[T].members.filter(_.isMethod == false).toSeq
  5. fields.foreach(x => {
  6. b[x.getMyType]() // How to pass field's "Type" into generic typed function?
  7. })
  8. }
  9. def b[T](): Unit = ???
  10. a[Person]()

From the above example, I am interested in calling a[Person]() and within a(), use reflection to obtain the fields from Person to make calls into b[?]() using each field's type.

答案1

得分: 3

以下是您要翻译的内容:

是否可以将从Symbol或Type对象派生的类型传递给泛型类型的函数?

方法b的类型参数T必须在编译时知道,但x.typeSignature只在运行时知道。

您可以尝试使用编译时反射而不是运行时反射。然后,x.typeSignature将在宏的运行时(主要代码的编译时)变为已知。

  1. // 宏子项目
  2. import scala.language.experimental.macros
  3. import scala.reflect.macros.blackbox
  4. def a[T](): Unit = macro aImpl[T]
  5. def aImpl[T: c.WeakTypeTag](c: blackbox.Context)(): c.Tree = {
  6. import c.universe._
  7. val fields: Seq[Symbol] = weakTypeOf[T].members.filter(_.isMethod == false).toSeq
  8. val bCalls = fields.map(x =>
  9. q"b[${x.typeSignature}]()"
  10. )
  11. q"..$bCalls"
  12. }
  13. // 主要子项目
  14. case class Address(street: String, city: String, state: String, zipCode: String)
  15. case class Person(name: String, age: Int, address: Address)
  16. def b[T](): Unit = ???
  17. a[Person]()
  18. // scalac: {
  19. // b[App.Address]();
  20. // b[Int]();
  21. // b[String]()
  22. //}

类似的事情也可以使用Shapeless完成。

  1. import shapeless.ops.hlist.{FillWith, Mapper}
  2. import shapeless.{Generic, HList, Poly0, Poly1}
  3. def b[T](): Unit = println("b")
  4. object bPoly extends Poly1 {
  5. implicit def cse[X]: Case.Aux[X, Unit] = at(_ => b[X]())
  6. }
  7. object nullPoly extends Poly0 {
  8. implicit def cse[X]: Case0[X] = at(null.asInstanceOf[X])
  9. }
  10. def a[T] = new PartiallyAppliedA[T]
  11. class PartiallyAppliedA[T] {
  12. def apply[L <: HList]()(implicit
  13. generic: Generic.Aux[T, L],
  14. mapper: Mapper[bPoly.type, L],
  15. fillWith: FillWith[nullPoly.type, L]
  16. ): Unit = mapper(fillWith())
  17. }
  18. case class Address(street: String, city: String, state: String, zipCode: String)
  19. case class Person(name: String, age: Int, address: Address)
  20. a[Person]()
  21. //b
  22. //b
  23. //b

或者,如果您确实想使用运行时反射,您必须推迟b[...]()的编译直到运行时。您可以使用toolbox实现这一点。

  1. import scala.reflect.runtime.currentMirror
  2. import scala.reflect.runtime.universe._
  3. import scala.tools.reflect.ToolBox
  4. val toolbox = currentMirror.mkToolBox()
  5. def a[T: TypeTag](): Unit = {
  6. val fields: Seq[Symbol] = typeOf[T].members.filter(_.isMethod == false).toSeq
  7. val bCalls = fields.map(x =>
  8. q"b[${x.typeSignature}]()"
  9. )
  10. toolbox.eval(q"""
  11. import Obj._
  12. ..$bCalls
  13. """)
  14. }
  15. object Obj {
  16. def b[T](): Unit = println("b")
  17. }
  18. case class Address(street: String, city: String, state: String, zipCode: String)
  19. case class Person(name: String, age: Int, address: Address)
  20. a[Person]()
  21. //b
  22. //b
  23. //b
英文:

> is it possible to pass a type derived from a Symbol or Type object into a generic typed function?

Type parameter T of method b must be known at compile time but x.typeSignature becomes known only at runtime.

You can try to use compile-time reflection rather than runtime one. Then x.typeSignature becomes known at runtime of the macro, which is compile time of the main code.

  1. // macros subproject
  2. import scala.language.experimental.macros
  3. import scala.reflect.macros.blackbox
  4. def a[T](): Unit = macro aImpl[T]
  5. def aImpl[T: c.WeakTypeTag](c: blackbox.Context)(): c.Tree = {
  6. import c.universe._
  7. val fields: Seq[Symbol] = weakTypeOf[T].members.filter(_.isMethod == false).toSeq
  8. val bCalls = fields.map(x =&gt;
  9. q&quot;b[${x.typeSignature}]()&quot;
  10. )
  11. q&quot;..$bCalls&quot;
  12. }
  13. // main subproject
  14. case class Address(street: String, city: String, state: String, zipCode: String)
  15. case class Person(name: String, age: Int, address: Address)
  16. def b[T](): Unit = ???
  17. a[Person]()
  18. // scalac: {
  19. // b[App.Address]();
  20. // b[Int]();
  21. // b[String]()
  22. //}

Similar thing can be done with Shapeless.

  1. import shapeless.ops.hlist.{FillWith, Mapper}
  2. import shapeless.{Generic, HList, Poly0, Poly1}
  3. def b[T](): Unit = println(&quot;b&quot;)
  4. object bPoly extends Poly1 {
  5. implicit def cse[X]: Case.Aux[X, Unit] = at(_ =&gt; b[X]())
  6. }
  7. object nullPoly extends Poly0 {
  8. implicit def cse[X]: Case0[X] = at(null.asInstanceOf[X])
  9. }
  10. def a[T] = new PartiallyAppliedA[T]
  11. class PartiallyAppliedA[T] {
  12. def apply[L &lt;: HList]()(implicit
  13. generic: Generic.Aux[T, L],
  14. mapper: Mapper[bPoly.type, L],
  15. fillWith: FillWith[nullPoly.type, L]
  16. ): Unit = mapper(fillWith())
  17. }
  18. case class Address(street: String, city: String, state: String, zipCode: String)
  19. case class Person(name: String, age: Int, address: Address)
  20. a[Person]()
  21. //b
  22. //b
  23. //b

Alternatively, if you really want to use runtime reflection, you have to postpone compilation of b[...]() till runtime. You can do this with toolbox.

  1. import scala.reflect.runtime.currentMirror
  2. import scala.reflect.runtime.universe._
  3. import scala.tools.reflect.ToolBox
  4. val toolbox = currentMirror.mkToolBox()
  5. def a[T: TypeTag](): Unit = {
  6. val fields: Seq[Symbol] = typeOf[T].members.filter(_.isMethod == false).toSeq
  7. val bCalls = fields.map(x =&gt;
  8. q&quot;b[${x.typeSignature}]()&quot;
  9. )
  10. toolbox.eval(q&quot;&quot;&quot;
  11. import Obj._
  12. ..$bCalls
  13. &quot;&quot;&quot;)
  14. }
  15. object Obj {
  16. def b[T](): Unit = println(&quot;b&quot;)
  17. }
  18. case class Address(street: String, city: String, state: String, zipCode: String)
  19. case class Person(name: String, age: Int, address: Address)
  20. a[Person]()
  21. //b
  22. //b
  23. //b

huangapple
  • 本文由 发表于 2020年8月14日 09:13:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/63405194.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定