如何在Scala中获取表达式的(静态)类型?

时间:2019-07-11 14:00:44

标签: scala code-generation typeof scala-macros scala-meta

Scala是否与GCC的typeof extension等效? (还是C ++ decltype?)

我正在生成引用一些外部代码(可能尚不可用)的代码,并且我需要一种方法来在方法定义中引用该代码的类型

对于单例对象,我可以使用Foo.type,但是如果Foo是一个任意表达式,则不起作用。

更新

这是一个显示问题的简化示例:

def f(x: typeof(Foo))(implicit M: Monoid[typeof(Foo)]) =
  M.append(Foo, M.append(x, Foo))

我正在处理的代码对Foo一无所知,只是它是Scala表达式的字符串表示形式。它将上面的代码输出到.scala文件中,以后将作为单独项目的一部分进行编译。

当然typeof(Foo)位不起作用。仅当Foo.type是单身人士时,才能使用Foo

基本上,我想知道是否有可以代替typeof(Foo)的东西可以用于任意Scala表达式。

2 个答案:

答案 0 :(得分:2)

在Scala中没有这种typeof

我们可以尝试修改添加类型参数的方法

def f[F](foo: F)(x: F)(implicit M: Monoid[F]) =
  M.append(foo, M.append(x, foo))

f(Foo)(...)那样调用它,其中Foo是要替换的表达式,然后应在编译时推断出F

否则,我可以想象以下工作流程。我们可以使用Scalameta的SemanticDBFoo本身的字符串表示形式生成表达式Foo类型的字符串表示形式,然后插入表达式Foo的字符串表示形式,并由此生成字符串表示形式类型。

另一种选择是使用macro annotation

生成树
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class generate(foo: String) extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro generateMacro.impl
}

object generateMacro {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    import c.universe._
    val str: String = c.prefix.tree match {
      case q"new generate($s)" => c.eval[String](c.Expr(s))
    }
    val tree = c.typecheck(c.parse(str))
    val tpe = tree.tpe.widen
    annottees match {
      case q"$mods def $name[..$_](...$_): $_ = $_" :: _ =>
        q"""
            $mods def $name(x: $tpe)(implicit M: Monoid[$tpe]): $tpe =
              M.append($tree, M.append(x, $tree))
          """
    }
  }
}

@generate("1 + 1")
def f(): Unit = ()
// def f(x: Int)(implicit M: Monoid[Int]): Int = M.append(2, M.append(x, 2))

https://github.com/travisbrown/type-provider-examples/

https://docs.scala-lang.org/overviews/macros/typeproviders.html


实际上我想这与要求的很接近

class TypeOf[A](a: A) {
  type T = A
}

val tp = new TypeOf(Foo)

def f(x: tp.T)(implicit M: Monoid[tp.T]) = M.append(Foo, M.append(x, Foo))

答案 1 :(得分:0)

您是否有要使用的类型的引用类?否则定义一个自定义类,并使用:

classOf [Class_Name] 

等同于typeOf

如果您想了解自定义对象的类,请使用:

object_name.getClass