标签: scala-macros

Scala Macros:检查某个注释

感谢上一个问题的答案,我能够创建一个函数宏,使得它返回一个Map将每个字段名称映射到它的类值,例如

...

trait Model

case class User (name: String, age: Int, posts: List[String]) extends Model {
  val numPosts: Int = posts.length

  ...

  def foo = "bar"

  ...
}
Run Code Online (Sandbox Code Playgroud)

所以这个命令

val myUser = User("Foo", 25, List("Lorem", "Ipsum"))

myUser.asMap
Run Code Online (Sandbox Code Playgroud)

回报

Map("name" -> "Foo", "age" -> 25, "posts" -> List("Lorem", "Ipsum"), "numPosts" -> 2)
Run Code Online (Sandbox Code Playgroud)

这就是生成Tuples的Map地方(见Travis Brown的回答):

...

val pairs = weakTypeOf[T].declarations.collect {
  case m: MethodSymbol if m.isAccessor =>
    val name = c.literal(m.name.decoded)
    val …
Run Code Online (Sandbox Code Playgroud)

annotations scala scala-macros

11
推荐指数
1
解决办法
931
查看次数

自定义Scala枚举,搜索最优雅的版本

对于我的一个项目,我已经实现了一个基于的枚举

trait Enum[A] {
  trait Value { self: A =>
    _values :+= this
  }
  private var _values = List.empty[A]
  def values = _values
}

sealed trait Currency extends Currency.Value
object Currency extends Enum[Currency] {
  case object EUR extends Currency
  case object GBP extends Currency
}
Run Code Online (Sandbox Code Playgroud)

来自Case对象与Scala中的枚举.我工作得很好,直到遇到以下问题.Case对象似乎很懒惰,如果我使用Currency.value,我可能实际上得到一个空列表.可以在启动时对所有枚举值进行调用,以便填充值列表,但这将有点击败这一点.

因此,我冒险进入scala反射的黑暗和未知的地方,并根据以下SO答案提出了这个解决方案.我是否可以获得所有案例对象的编译时列表,这些案例对象派生自Scala中的密封父代?我怎样才能获得通过斯卡拉2.10反射提到了实际的对象?

import scala.reflect.runtime.universe._

abstract class Enum[A: TypeTag] {
  trait Value

  private def sealedDescendants: Option[Set[Symbol]] = {
    val symbol = typeOf[A].typeSymbol
    val internal = symbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol]
    if (internal.isSealed)
      Some(internal.sealedDescendants.map(_.asInstanceOf[Symbol]) - symbol) …
Run Code Online (Sandbox Code Playgroud)

enums scala scala-2.10 scala-macros

11
推荐指数
1
解决办法
2154
查看次数

如何测试Scala宏?

在scala宏上执行测试的建议方法是什么?

我意识到由于需要单独编译,需要两个项目.如有必要,此步骤可以接受并且大部分都是清楚的.

但是,如何断言宏扩展失败呢?如果没有一些特殊功能,测试用例将无法编译,因此整个测试项目将无法编译.

我认为这个断言需要另一个形式的宏

errors(code: => _): List[CompileError]
Run Code Online (Sandbox Code Playgroud)

它返回内部宏的编译错误.如果他们应该发出警告,那么测试警告也是必需的......等等......

Scala宏是否有一些现有的测试工具?

scala scala-macros

11
推荐指数
1
解决办法
683
查看次数

StringContext和宏:一个简单的例子

我正在尝试实现一个StringContext扩展,这将允许我写这个:

val tz = zone"Europe/London" //tz is of type java.util.TimeZone
Run Code Online (Sandbox Code Playgroud)

但有一点需要注意,如果提供的时区无效(假设可以在编译时确定),它将无法编译.

这是一个辅助函数:

def maybeTZ(s: String): Option[java.util.TimeZone] =
  java.util.TimeZone.getAvailableIDs collectFirst { case id if id == s =>
    java.util.TimeZone.getTimeZone(id)
  }
Run Code Online (Sandbox Code Playgroud)

我可以很容易地创建一个非宏实现:

scala> implicit class TZContext(val sc: StringContext) extends AnyVal {
 |   def zone(args: Any *) = {
 |     val s = sc.raw(args.toSeq : _ *)
 |     maybeTZ(s) getOrElse sys.error(s"Invalid zone: $s")
 |   }
 | }
Run Code Online (Sandbox Code Playgroud)

然后:

scala> zone"UTC"
res1: java.util.TimeZone = sun.util.calendar.ZoneInfo[id="UTC",offset=0,...
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.如果时区是无意义的(例如zone"foobar"),那么编译不会失败; 代码在运行时失效.我想将它扩展到一个宏,但是,尽管阅读了文档 …

scala scala-macros

10
推荐指数
2
解决办法
1567
查看次数

scala 2.10.2调用泛型类型的"宏方法"不起作用

我定义了以下宏来将case字段转换为map

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

    def asMap_impl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]) = {
      import c.universe._

      val mapApply = Select(reify(Map).tree, newTermName("apply"))

      val pairs = weakTypeOf[T].declarations.collect {
        case m: MethodSymbol if m.isCaseAccessor =>
          val name = c.literal(m.name.decoded)
          val value = c.Expr(Select(t.tree, m.name))
          reify(name.splice -> value.splice).tree
      }

      c.Expr[Map[String, Any]](Apply(mapApply, pairs.toList))
    }
Run Code Online (Sandbox Code Playgroud)

并且方法实现

def asMap[T](t: T) = macro asMap_impl[T]
Run Code Online (Sandbox Code Playgroud)

然后我定义一个案例类来测试它

case class User(name : String)
Run Code Online (Sandbox Code Playgroud)

它工作正常(使用scala repl):

 scala> asMap(User("foo")) res0:
 scala.collection.immutable.Map[String,String] = Map(name -> foo)
Run Code Online (Sandbox Code Playgroud)

但是当我用另一个泛型方法包装此方法时

def printlnMap[T](t: T) = println(asMap(t))
Run Code Online (Sandbox Code Playgroud)

此方法始终打印空地图:

scala> printlnMap(User("foo"))
Map() …
Run Code Online (Sandbox Code Playgroud)

generics scala scala-macros

10
推荐指数
1
解决办法
1347
查看次数

Scala宏和单独的编译单元

这个限制将来会被克服吗?或者有什么办法解决这个我不知道的事情?

现在我有一个项目,我想使用宏,但他们需要依赖于该项目的特定类型.有一个单独的宏编译单元需要我引入另一个来保存常见类型,我不愿意每次写宏时都这样做.

macros jvm scala compilation scala-macros

10
推荐指数
1
解决办法
487
查看次数

如何将参数/设置传递给Scala宏?

如何将参数/设置传递给Scala宏?

这些设置不应该是全局的,而是每次宏调用.

我想要的是类似的东西:

def a(param: Int) = macro internalMacro("setting 1")
def b(param: Int) = macro internalMacro("setting 2")
Run Code Online (Sandbox Code Playgroud)

setting 1setting 2应然后是恒定值,从宏观中访问,这样我就可以使内部行为依赖于他们.

scala parameter-passing scala-macros

10
推荐指数
1
解决办法
2002
查看次数

创建一个含糊的低优先级隐式

考虑io包装中提供的默认编解码器。

implicitly[io.Codec].name  //res0: String = UTF-8
Run Code Online (Sandbox Code Playgroud)

它是“低优先级”隐式的,因此很容易覆盖而不会产生歧义。

implicit val betterCodec: io.Codec = io.Codec("US-ASCII")

implicitly[io.Codec].name  //res1: String = US-ASCII
Run Code Online (Sandbox Code Playgroud)

提高优先级也很容易。

import io.Codec.fallbackSystemCodec
implicit val betterCodec: io.Codec = io.Codec("US-ASCII")

implicitly[io.Codec].name  //won't compile: ambiguous implicit values
Run Code Online (Sandbox Code Playgroud)

但是我们可以朝相反的方向前进吗?我们可以创建一个低级别的隐式来禁用(“歧义化”)默认值吗?我一直在研究优先级方程式,并使用低优先级隐式变量进行操作,但尚未创建默认值的歧义。

scala implicit scala-macros scala-compiler

10
推荐指数
1
解决办法
421
查看次数

Scala 类型约束来检查参数值

我正在尝试在 Scala 中实现康威的超现实数字。超现实数是递归定义的——作为一对超现实数的集合,称为左和右,这样右集中的任何元素都不小于或等于左集中的任何元素。这里超现实数之间的关系“小于或等于”也是递归定义的:我们说x ? Ÿ如果

  • x的左集中没有元素a使得y ? ,和
  • y的右集中没有元素b使得b ? ×

我们首先将零定义为一对空集,然后使用零来定义 1 和 -1,依此类推。

我无法弄清楚如何在编译时强制执行超现实数字的定义。这就是我现在所拥有的:

case class SurrealNumber(left: Set[SurrealNumber], right: Set[SurrealNumber]) {
  if ((for { a <- left; b <- right; if b <= a } yield (a, b)).nonEmpty)
    throw new Exception
  def <=(other: SurrealNumber): Boolean =
    !this.left.exists(other <= _) && !other.right.exists(_ <= this)
}

val zero = SurrealNumber(Set.empty, Set.empty)
val one = …
Run Code Online (Sandbox Code Playgroud)

types scala type-level-computation shapeless scala-macros

10
推荐指数
1
解决办法
212
查看次数

测试c.universe.Type是否可分配给宏中的其他类型

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

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

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

scala scala-macros

9
推荐指数
1
解决办法
201
查看次数