以下宏粘贴自http://docs.scala-lang.org/overviews/quasiquotes/usecases.html:
import reflect.macros.Context
import language.experimental.macros
val universe = reflect.runtime.universe; import universe._
import reflect.runtime.currentMirror
import tools.reflect.ToolBox
val toolbox = currentMirror.mkToolBox()
object debug {
def apply[T](x: =>T): T = macro impl
def impl(c: Context)(x: c.Tree) = { import c.universe._
val q"..$stats" = x
val loggedStats = stats.flatMap { stat =>
val msg = "executing " + showCode(stat)
List(q"println($msg)", stat)
}
q"..$loggedStats"
}
}
Run Code Online (Sandbox Code Playgroud)
它在 Scala 2.11.1 中产生此错误消息:
Q.scala:9: error: macro implementation reference has wrong shape. required:
macro [<static object>].<method name>[[<type …Run Code Online (Sandbox Code Playgroud) 使用 Scala 宏,我想访问函数 f 的源代码。
这是我的问题的简化示例:
def logFImplementation(f: => Boolean) {
val sourceCodeOfF: String = ... // <-- how to get source code of f??
println("Scala source of f=" + sourceCodeOfF)
}
Run Code Online (Sandbox Code Playgroud)
因此对于:
logFImplementation { val i = 5; List(1, 2, 3); true }
Run Code Online (Sandbox Code Playgroud)
它应该打印:
Scala source of f=val i: Int = 5; immutable.this.List.apply[Int](1, 2, 3); true
Run Code Online (Sandbox Code Playgroud)
(现在我测试了宏以在运行时访问源代码文本,它非常有用,{ val i = 5; List(1, 2, 3); true }.logValueImpl但f.logValueImpl它只是打印f.)
感谢您的任何建议。
鉴于此,我想编写一个宏:
@MetaRest case class User(
@get id : Int,
@get @post @patch name : String,
@get @post email : String,
registeredOn : DateTime
)
Run Code Online (Sandbox Code Playgroud)
生成以下代码段:
object User {
case class Get(id: Int, name: String, email: String)
case class Post(name: String, email: String
case class Patch(name: Option[String]) // Note - the Option type here!
}
Run Code Online (Sandbox Code Playgroud)
我在这里取得了不错的进展:https : //github.com/pathikrit/metarest
这是我的尝试:https : //github.com/pathikrit/metarest/blob/master/src/main/scala/com/github/pathikrit/MetaRest.scala
class MetaRest extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro MetaRest.impl
}
object MetaRest {
sealed trait …Run Code Online (Sandbox Code Playgroud) scala scala-macros scala-2.11 scala-macro-paradise scalameta
我有以下宏:
package macros
import scala.reflect.macros.blackbox.Context
object CompileTimeAssertions {
def mustBeCaseClass[T]: Unit =
macro CompileTimeAssertionsImpl.mustBeCaseClass[T]
}
object CompileTimeAssertionsImpl {
def mustBeCaseClass[T: c.WeakTypeTag](c: Context): c.Expr[Unit] = {
import c.universe._
val symbol = c.weakTypeTag[T].tpe.typeSymbol
if (!symbol.isClass || !symbol.asClass.isCaseClass) {
c.error(c.enclosingPosition, s"${symbol.fullName} must be a case class")
}
reify(Unit)
}
}
Run Code Online (Sandbox Code Playgroud)
它在不涉及泛型时有效,但在以下情况下失败:
import macros.CompileTimeAssertions._
import org.scalatest.{Matchers, WordSpec}
case class ACaseClass(foo: String, bar: String)
class NotACaseClass(baz: String)
class MacroSpec extends WordSpec with Matchers {
"the mustBeCaseClass macro" should {
"compile when passed a case class" …Run Code Online (Sandbox Code Playgroud) 我正在使用一个 csv 库,它接受一个案例类并将其转换为行供我阅读。
语法非常接近File(path).asCsvReader[caseClass]. 链接到这里的库
然而问题是我想从数据库中的表生成案例类。我可以接收数据库中的表以及列的类型(Int、Long、Double、String 等),但我不知道如何使用该数据动态创建案例类,因为我在编译时不知道这些信息。
正因为如此,我也无法使用宏,因为我不知道宏编译时的表数据。
那么,一旦收到表数据,然后将该案例类传递给 csv 库,我将如何动态创建该案例类?
我试图在编译时列出包中的所有类。
让我们定义一个具有以下结构的项目:
com.main
Main.scala
com.package
Method.scala
com.package.method1
Method1.scala
com.package.method2
Method2.scala
Run Code Online (Sandbox Code Playgroud)
在哪里:
方法.scala
abstract class Method(val name: String) {
}
Run Code Online (Sandbox Code Playgroud)
Method1.scala 和 Method2.scala (更改各自的名称)
class Method1 extends Method(name = "Method1") {
}
Run Code Online (Sandbox Code Playgroud)
我想从 Main.scala 获取 com.package._ 中定义的类列表,如下所示:
object Main() {
val names = List("Method1", "Method2")
}
Run Code Online (Sandbox Code Playgroud)
我可以对名称进行硬编码(如图所示),但我想知道是否可以在编译时获取这些名称。我知道在运行时可以使用http://software.clapper.org/classutil/
我有两个类,将它们称为Foo和Fizz。Foo使用一个被调用的注释宏expand来为其某些方法创建别名(实际实现所做的不仅仅是创建别名,但简单版本仍然会出现以下问题)。为简单起见,假设expand宏简单地获取带注释的类中的所有方法,并制作它们的副本,将“Copy”附加到方法名称的末尾,然后将调用转发到原始方法。
我的问题是,如果我使用expand宏 on Foo,它会创建一个Foo#bar名为的方法的副本barCopy,当barCopy在另一个类中调用时Fizz,一切都会编译,但 scaladoc 生成失败,如下所示:
[error] ../src/main/scala/Foo.scala:11: value barCopy is not a member of Foo
[error] def str = foo.barCopy("hey")
[error] ^
[info] No documentation generated with unsuccessful compiler run
Run Code Online (Sandbox Code Playgroud)
如果我删除标记正在复制的方法 ( Foo#bar)的 scaladoc ,该sbt doc命令将再次运行。就好像 scaladoc 生成器在不使用启用的宏天堂插件的情况下调用编译器的早期阶段一样,但如果从有问题的方法中删除文档,它会以某种方式工作。
这是expand宏:
import scala.annotation.{ StaticAnnotation, compileTimeOnly }
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
@compileTimeOnly("You must enable the macro …Run Code Online (Sandbox Code Playgroud) 我尝试使用https://github.com/estatico/scala-newtype,如下所示:
import io.estatico.newtype.macros.newtype
import cats._
import io.databaker.env._
@newtype case class DbUrl(v: String)
@newtype case class DbUser(v: String)
@newtype case class DbPw(v: String)
final case class DbParams(url: DbUrl, user: DbUser, pw: DbPw)
trait DbConnector[F[_]] {
def read(url: DbUrl, user: DbUser, pw: DbPw): F[DbParams]
}
object DbConnector {
def impl[F[_] : MonadError[*[_], Throwable]](env: Environment[F])
: DbConnector[F] =
new LiveDbConnector[F](env)
}
Run Code Online (Sandbox Code Playgroud)
编译器抱怨:
[error] ../db/DbConnector.scala:7:2: top-level class without companion can only expand either into an eponymous class or into a block consisting …Run Code Online (Sandbox Code Playgroud) 我正在编写宏将类型描述转换为单例类型:
object Type2String {
def apply[I]: Witness.Lt[String] = macro Macros.apply[I]
final class Macros(val c: whitebox.Context) extends MWithReflection {
import c.universe._
def apply[A: WeakTypeTag]: Tree = {
val tt: Type = weakTypeOf[A]
val str = tt.toString
// val vv = viz(tt)
q"shapeless.Witness.mkWitness[$str]($str)"
}
}
}
Run Code Online (Sandbox Code Playgroud)
问题是因为 A 只有一个 WeakTypeTag。它无法从泛型类型中提取正确的信息:
case class ^^[T1, T2]() {
final val wTSelf = Type2String[^^[T1, T2]]
}
val e1 = ^^[Int, String]()
e1.wTSelf
Run Code Online (Sandbox Code Playgroud)
这给出了错误的见证人类型: shapeless.Witness.Aux[String("T1 ^^ T2")]
所以我的问题是:
现在是编译时,类型信息应该是完全可见的,为什么T1和T2被擦除了?
如何修复此程序以提供正确的类型信息:
shapeless.Witness.Aux[String("Int ^^ String")]
?
使用镜像在 Scala 3 中执行类型类派生时,是否有一种干净的方法来访问案例类字段的默认值?例如:
case class Foo(s: String = "bar", i: Int, d: Double = Math.PI)
Run Code Online (Sandbox Code Playgroud)
Mirror.Product.MirroredElemLabels将被设置为("s", "i", "d")。有没有类似的东西:(Some["bar"], None, Some[3.141592653589793])?
如果不能,这可以使用宏来实现吗?我可以同时使用镜像和宏来派生类型类实例吗?
scala ×10
scala-macros ×10
scala-2.11 ×2
jvm ×1
macros ×1
reflection ×1
scala-2.13 ×1
scala-3 ×1
scala-cats ×1
scaladoc ×1
scalameta ×1
slick ×1
typeclass ×1