Как получить (статический) тип выражения в Scala? - PullRequest
0 голосов
/ 11 июля 2019

Имеет ли Scala какой-либо эквивалент typeof расширения GCC ?(Или 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 ]

2 голосов
/ 12 июля 2019

В Scala нет typeof такого рода.

Мы можем попытаться изменить метод, добавив параметр типа

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

и назовите его как f(Foo)(...), где Foo - выражение, которое нужно заменить, тогда F должно быть выведено после компиляции.

В противном случае я могу представить себе следующий рабочий процесс. Мы можем сгенерировать строковое представление типа выражения Foo из строкового представления самого Foo с помощью SemanticDB Скаламеты, а затем вставить строковое представление выражения Foo и это сгенерированное строковое представление типа.

Еще одним вариантом является создание дерева с макроаннотацией

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 / обзоры / макросы / 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))
0 голосов
/ 11 июля 2019

У вас есть справочный класс для типа, который вы хотите использовать?Еще определите пользовательский класс и используйте:

classOf [Class_Name] 

эквивалентно typeOf

И если вы пытаетесь узнать класс вашего пользовательского объекта, тогда используйте:

object_name.getClass
...