gpt4 book ai didi

scala - 测试 c.universe.Type 是否可分配给宏中的另一种类型

转载 作者:行者123 更新时间:2023-12-02 08:08:01 25 4
gpt4 key购买 nike

我正在尝试编写一个宏,它采用一个带有 java bean 接口(interface)的类和一个 case 类,并创建一对用于在它们之间进行映射的方法。

我试图检查每个属性的类型是否匹配,但是 java bean 中的类型是例如java.lang.Long,case类中的类型是scala.Long。

我的问题是,给定这两个的 c.universe.Type 对象,有没有办法测试它们之间是否存在隐式转换?即测试我是否可以将一个传递给需要另一个的方法。

最佳答案

如果你想检查是否存在隐式转换,可以使用c.inferImplicitView

概念证明:

scala> :paste
// Entering paste mode (ctrl-D to finish)

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros

def test[T,S,R](value: T, func: S => R): R = macro Macro.myMacro[T,S,R]

object Macro {
def myMacro[T: c.WeakTypeTag,S: c.WeakTypeTag,R](c: Context)(value: c.Tree, func: c.Tree): c.Tree = {
import c.universe._
val view = c.inferImplicitView(value, weakTypeOf[T], weakTypeOf[S])
if (view == EmptyTree)
c.abort(c.enclosingPosition, "Cannot apply function")
else
q"$func($value)"
}
}

// Exiting paste mode, now interpreting.

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
defined term macro test: [T, S, R](value: T, func: S => R)R
defined object Macro

scala> test(3L, (l: java.lang.Long) => l.toString)
res20: String = 3

scala> test(3L, (l: java.lang.Integer) => l.toString)
<console>:23: error: Cannot apply function
test(3L, (l: java.lang.Integer) => l.toString)
^

如果您没有,显然如果您执行c.inferImplicitView(EmptyTree,weakTypeOf[T],weakTypeOf[S]),它也可以工作。

<小时/>

更接近实际问题的更复杂的示例:

scala> :paste
// Entering paste mode (ctrl-D to finish)

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros

def mapBetween[JB,CC](jb: JB): CC = macro Macro.myMacro[JB,CC]

object Macro {
def myMacro[JB: c.WeakTypeTag, CC: c.WeakTypeTag](c: Context)(jb: c.Tree): c.Tree = {
import c.universe._
val jbTpe = weakTypeOf[JB]
val ccTpe = weakTypeOf[CC]
val constructor = ccTpe.members.filter(m =>
m.isConstructor && m.name != TermName("$init$")
).head.asMethod
if(constructor.paramLists.size != 1 || constructor.paramLists.head.size != 1)
c.abort(c.enclosingPosition, "not supported :(")
val ccParam = constructor.paramLists.head.head
val ccParamType = ccParam.typeSignature
val ccParamName = ccParam.name.toString

val jbGetter = jbTpe.member(TermName(s"get${ccParamName.head.toUpper + ccParamName.tail}"))
val getterType = jbGetter.asMethod.returnType

val view = c.inferImplicitView(EmptyTree, getterType, ccParamType)
if (view == EmptyTree)
c.abort(c.enclosingPosition, "Cannot apply function")
else
q"new ${ccTpe.typeSymbol.name.toTypeName}($jb.${jbGetter.name.toTermName})"
}
}

// Exiting paste mode, now interpreting.

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
defined term macro mapBetween: [JB, CC](jb: JB)CC
defined object Macro

scala> case class CaseClass(foo: Int)
defined class CaseClass

scala> class JavaBean{ def getFoo(): java.lang.Integer = 42 }
defined class JavaBean

scala> mapBetween[JavaBean,CaseClass](new JavaBean)
res0: CaseClass = CaseClass(42)

scala> case class CaseClass(foo: Int)
defined class CaseClass

scala> class JavaBean{ def getFoo(): java.lang.Double = 42.0 }
defined class JavaBean

scala> mapBetween[JavaBean,CaseClass](new JavaBean)
<console>:27: error: Cannot apply function
mapBetween[JavaBean,CaseClass](new JavaBean)
^

关于scala - 测试 c.universe.Type 是否可分配给宏中的另一种类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31141220/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com