我有一个类型resultType的Context.this.type#c#universe#Type.我需要将它与Unit类型相匹配.我试过了
resultType match {
case q"Unit" => ...
}
Run Code Online (Sandbox Code Playgroud)
但我想这Unit只是一个字符串文字,显然不匹配.如何通过quasiqotes匹配类型?
我也尝试过
resultType match {
case TypeRef(ThisType(_), Symbol("scala.Unit"), _) => ...
}
Run Code Online (Sandbox Code Playgroud)
但有一个错误:
[error] pattern type is incompatible with expected type;
[error] found : Symbol
[error] required: Context.this.c.universe.SymbolContextApi
Run Code Online (Sandbox Code Playgroud)
如何以这种方式匹配类型?
我想在Scala中,我的宏注释会采取另一种类型的参数使用宏注解.然后,它会使用Scala的反射来看看式传递,并添加一些方法如appropriate.Eg.
trait MyTrait {
def x: Int
def y: Float
}
@MyAnnotation class MyClass //<-- somehow, this annotation should reference MyTrait
class MyAnnotation(val target: Any) extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro MyAnnotationImpl.impl
}
object MyAnnotationImpl {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
// if I can get a handle on the type MyTrait in here
// then I can call .members on it, etc.
...
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,与使用Scala宏中的Scala反射相同,除了使用宏注释.但是,当我尝试使用TypeTag模拟我的宏注释时
class MyAnnotation[T](val target: Any) extends StaticAnnotation { …Run Code Online (Sandbox Code Playgroud) 我正在寻找某种通用参数的上限,以T确保这T是一个特征。
class Foo
trait Bar
def f[A ??? IsATrait] = ???
// f[Foo] Won't compile
f[Bar] // this is fine
Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一个宏来简化一些与 monad 相关的代码(我使用cats 1.6.0 作为Monads)。现在我只想能够编写lift[F](a)whereF是一个一元类型的构造函数,并将其扩展为a.pure[F]. 看起来很简单,但我无法让它工作。
现在我有这个代码来帮助类型推断:
object Macros {
class LiftPartiallyApplied[F[_]] {
def apply[A](a: A): F[A] = macro MacroImpl.liftImpl[F, A]
}
def lift[F[_]] = new LiftPartiallyApplied[F]
}
Run Code Online (Sandbox Code Playgroud)
对于宏的实际实现:
object MacroImpl {
def liftImpl[F[_], A](c: blackbox.Context)(a: c.Tree)(implicit tt: c.WeakTypeTag[F[_]]): c.Tree = {
import c.universe._
q"$a.pure[${tt.tpe.typeConstructor}]"
}
}
Run Code Online (Sandbox Code Playgroud)
现在我可以像这样调用宏lift[List](42),它会扩展为42.pure[List],太好了。但是当我用更复杂的类型调用它时,比如lift[({type F[A] = Either[String, A]})#F](42),它会扩展到42.pure[Either],这显然是坏的,因为它Either是一个二进制类型的构造函数而不是一元类型的构造函数。问题是我只是不知道该放什么而不是${tt.tpe.typeConstructor}……
// 编辑:由于人们显然无法重现该问题,因此我制作了一个完整的存储库:https : //github.com/mberndt123/macro-experiment 我现在将尝试找出 Dmytro 和我自己的项目之间的区别是。
我正在试验它的一个库中提供的 scala 的精炼类型特性:
https://github.com/fthomas/refined
下面的代码代表一个简单的案例:
import eu.timepit.refined.auto._
import shapeless.{Witness => W}
type Vec5 = List[Int] Refined Size[Equal[W.`5`.T]]
val v1: Vec5 = List(1, 2, 3, 4, 5)
val v2: Vec5 = List(1 to 5: _*)
Run Code Online (Sandbox Code Playgroud)
尝试编译它时,我收到以下错误:
[Error] /home/peng/git/scalaspike/common/src/test/scala/com/tribbloids/spike/refined_spike/Example.scala:32: compile-time refinement only works with literals
[Error] /home/peng/git/scalaspike/common/src/test/scala/com/tribbloids/spike/refined_spike/Example.scala:34: compile-time refinement only works with literals
[Error] /home/peng/git/scalaspike/common/src/test/scala/com/tribbloids/spike/singleton_ops_spike/Example.scala:32: Cannot prove requirement Require[...]
three errors found
Run Code Online (Sandbox Code Playgroud)
应该注意的是,v1 和 v2 都可以在编译时轻松评估和内联,但是 Scala 编译器似乎拒绝这样做,并且对于Listtype 似乎没有办法建议这一点。
那么这个功能怎么会有用呢?
我知道我可以像这样添加动态"字段":
import collection.mutable
class DynamicType extends Dynamic {
private val fields = mutable.Map.empty[String, Any].withDefault {key => throw new NoSuchFieldError(key)}
def selectDynamic(key: String) = fields(key)
def updateDynamic(key: String)(value: Any) = fields(key) = value
def applyDynamic(key: String)(args: Any*) = fields(key)
}
Run Code Online (Sandbox Code Playgroud)
然后我可以做这样的事情:
val foo = new DynamicType
foo.age = 23
foo.name = "Rick"
Run Code Online (Sandbox Code Playgroud)
但是,我想进一步扩展这一步并添加动态方法,例如:
foo.greet = (name: String) => s"Nice to meet you $name, my name is ${this.name}"
foo.greet("Nat"); //should return "Nice to meet you Nat, my name is Rick"
Run Code Online (Sandbox Code Playgroud)
我尝试将所有方法存储在单独的映射中,updateDynamic …
我有下一个代码,我想从值中提取默认参数.
//
def extractor[T] = macro extractorImpl[T]
def extractorImpl[T: c.WeakTypeTag](c: Context) = {
//first i got a type contructor
???
}
Run Code Online (Sandbox Code Playgroud)
我尝试attachments但attachments.all返回一个Set[Any](例如)SymbolSourceAttachment(val name: String = "new name")
SymbolSourceAttachment包含ValDef但我不知道如何从中提取SymbolSourceAttachment ValDef.
顺便说一句我应该得到一个 Map[String, String]("name" -> "new name")
例:
case class Person(name: String = "new name")
object Macro {
def extractor[T] = macro extractorImpl[T]
def extractorImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
c.weakTypeOf[T].declarations.collect {
case a: MethodSymbol if a.isConstructor =>
a.paramss.collect …Run Code Online (Sandbox Code Playgroud) 我想写一个返回类型依赖于参数的宏.简化示例:
def fun[T](methodName: String) = macro funImpl[T]
def funImpl[T: WeakTypeTag](c: Context)(methodName: c.Expr[String]): /* c.Expr[T => return type of T.methodName] */ = {
// return x => x.methodName
}
Run Code Online (Sandbox Code Playgroud)
显然,退出的退货类型funImpl是非法的.我试过简单地返回一个Tree,但这会产生一个错误:
[error] macro implementation has wrong shape:
[error] required: (c: scala.reflect.macros.Context): c.Expr[Any]
[error] found : (context: scala.reflect.macros.Context): context.Tree
[error] type mismatch for return type: c.universe.Tree does not conform to c.Expr[Any]
[error] def fun[T] = macro PrivateMethodMacro.funImpl[T]
[error] ^
Run Code Online (Sandbox Code Playgroud)
有可能写这样的宏吗?显然,如果将返回类型作为另一个类型参数传递,则可能会在回答中编写一个scala宏,其返回类型取决于参数?但这不是我想要的.
我正在诠释一个特征,例如:
@ScreenModel
trait TestTrait {
.......
}
Run Code Online (Sandbox Code Playgroud)
然后我得到了@ScreenModel的实现,例如:
def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val output : List[Tree] = annottees.map(_.tree) match {
case(cd @ q"$mods trait $name[..$tparams] extends ..$parents { ..$body }") :: Nil =>
val compObjVar = s"""{
import models.presentation.blocks.BlockModel;
class AAAA {
class BBBB {
}
}
}""";
val rawTree=c.parse(compObjVar)
val merged = q"{..$rawTree}";
merged :: Nil
case _ => c.abort(c.enclosingPosition, "Invalid test target")
}
c.Expr[Any](q"..$output")
}
Run Code Online (Sandbox Code Playgroud)
所以,我得到了:
"没有伴侣的顶级课程只能扩展为同名课程或者成块"
但是,如果我在AAA类中的AAA类之前移动导入,那么它可以工作:
val compObjVar = s"""{
class …Run Code Online (Sandbox Code Playgroud) 在一种称为scala(2.11)宏的方法中,是否有一种方法可以以编程方式确定a是否Type为a case class?
我正在研究的方法的API可以归结为:
def typeIsCaseClass(c: Context)(targetType: c.universe.Type): Boolean = {
// targetType "is case class?"
}
Run Code Online (Sandbox Code Playgroud)
如果需要,我愿意更改API。
scala-macros ×10
scala ×8
reflection ×3
case-class ×1
dynamic ×1
refined ×1
scala-2.10 ×1
scala-2.11 ×1
type-bounds ×1