Трейт scala.reflect.api.Constants
Трейт Constants extends AnyRef
Типовые члены
абстрактный тип Constant >: Null <: Universe.ConstantApi
Этот "виртуальный" класс-случай представляет собой интерфейс отражения для литеральных выражений, которые нельзя далее разбить или вычислить, например, «true», «0», «classOf[List]». Такие значения становятся частями абстрактного синтаксического дерева Scala, представляющего программу. Константы соответствуют разделу 6.24 «Выражения констант» Спецификации языка Scala.
Такие константы используются для представления литералов в абстрактных синтаксических деревьях (узел scala.reflect.api.Trees#Literal) и литеральных аргументов для аннотаций файлов классов Java (класс scala.reflect.api.Annotations#LiteralArgument).
К константам можно подходить с помощью совпадений и создавать их напрямую, как если бы они были классами-случаями:
assert(Constant(true).value == true)
Constant(true) match {
case Constant(s: String) => println("A string: " + s)
case Constant(b: Boolean) => println("A boolean value: " + b)
case Constant(x) => println("Something else: " + x)
}
Экземпляры Constant могут содержать определённые типы этих выражений:
-
Литералы примитивных типов (
Byte, Short, Int, Long, Float, Double, Char, Boolean и Unit) — представлены напрямую как соответствующие типыСтроковые литералы — представлены как экземпляры String.Ссылки на классы, обычно создаваемые с помощью scala.Predef#classOf — представлены как типы.Ссылки на значения перечислений — представлены как символы.Ссылки на классы представлены экземплярами scala.reflect.api.Types#Type (потому что когда компилятор Scala обрабатывает ссылку на класс, подлежащий класс во время выполнения может еще не быть скомпилирован). Для преобразования такой ссылки в класс во время выполнения следует использовать метод runtimeClass зеркала, такого как RuntimeMirror (простейший способ получить такое зеркало — использовать scala.reflect.runtime.currentMirror).
Ссылки на значения перечислений представлены экземплярами scala.reflect.api.Symbols#Symbol, которые в JVM указывают на методы, возвращающие основополагающие значения перечислений. Для проверки основного перечисления или получения значения во время выполнения ссылки на перечисление необходимо использовать scala.reflect.api.Mirrors#RuntimeMirror (простейший способ получения такого зеркала — снова scala.reflect.runtime.package#currentMirror).
Пример использования:
enum JavaSimpleEnumeration { FOO, BAR }
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface JavaSimpleAnnotation {
Class<?> classRef();
JavaSimpleEnumeration enumRef();
}
@JavaSimpleAnnotation(
classRef = JavaAnnottee.class,
enumRef = JavaSimpleEnumeration.BAR
)
public class JavaAnnottee {}
import scala.reflect.runtime.universe._
import scala.reflect.runtime.{currentMirror => cm}
object Test extends App {
val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs
def jarg(name: String) = jann(TermName(name)) match {
// Constant is always wrapped into a Literal or LiteralArgument tree node
case LiteralArgument(ct: Constant) => value
}
val classRef = jarg("classRef").value.asInstanceOf[Type]
// ideally one should match instead of casting
println(showRaw(classRef)) // TypeRef(ThisType(<empty>), JavaAnnottee, List())
println(cm.runtimeClass(classRef)) // class JavaAnnottee
val enumRef = jarg("enumRef").value.asInstanceOf[Symbol]
// ideally one should match instead of casting
println(enumRef) // value BAR
val siblings = enumRef.owner.info.decls
val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic)
println(enumValues) // Scope{
// final val FOO: JavaSimpleEnumeration;
// final val BAR: JavaSimpleEnumeration
// }
// doesn't work because of https://github.com/scala/bug/issues/6459
// val enumValue = mirror.reflectField(enumRef.asTerm).get
val enumClass = cm.runtimeClass(enumRef.owner.asClass)
val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null)
println(enumValue) // BAR
}
абстрактный класс ConstantApi extends AnyRef
абстрактный класс ConstantExtractor extends AnyRef
Абстрактные значения-члены
абстрактный val Constant: Universe.ConstantExtractor
Члены конкретных значений
final def !=(arg0: Any): Boolean
- Определяющие классы
- AnyRef → Any
final def ##(): Int
- Определяющие классы
- AnyRef → Any
def +(other: String): String
def ->[B](y: B): (Constants, B)
final def ==(arg0: Any): Boolean
- Определяющие классы
- AnyRef → Any
final def asInstanceOf[T0]: T0
- Определяющие классы
- Any
def clone(): AnyRef
- Атрибуты
- protected[java.lang]
- Определяющие классы
- AnyRef
- Аннотации
- @throws(classOf[java.lang.CloneNotSupportedException]) @native()
def ensuring(cond: (Constants) => Boolean, msg: => Any): Constants
def ensuring(cond: (Constants) => Boolean): Constants
def ensuring(cond: Boolean, msg: => Any): Constants
def ensuring(cond: Boolean): Constants
final def eq(arg0: AnyRef): Boolean
- Определяющие классы
- AnyRef
def equals(arg0: AnyRef): Boolean
- Определяющие классы
- AnyRef → Any
def finalize(): Unit
- Атрибуты
- protected[java.lang]
- Определяющие классы
- AnyRef
- Аннотации
- @throws(classOf[java.lang.Throwable])
def formatted(fmtstr: String): String
final def getClass(): Class[_ <: AnyRef]
- Классы определений
- AnyRef → Any
- Аннотации
- @native()
def hashCode(): Int
- Классы определений
- AnyRef → Any
- Аннотации
- @native()
final def isInstanceOf[T0]: Boolean
- Классы определений
- Any
final def ne(arg0: AnyRef): Boolean
- Классы определений
- AnyRef
final def notify(): Unit
- Классы определений
- AnyRef
- Аннотации
- @native()
final def notifyAll(): Unit
- Классы определений
- AnyRef
- Аннотации
- @native()
final def synchronized[T0](arg0: => T0): T0
- Классы определений
- AnyRef
def toString(): String
- Классы определений
- AnyRef → Any
final def wait(): Unit
- Классы определений
- AnyRef
- Аннотации
- @throws(classOf[java.lang.InterruptedException])
final def wait(arg0: Long, arg1: Int): Unit
- Классы определений
- AnyRef
- Аннотации
- @throws(classOf[java.lang.InterruptedException])
final def wait(arg0: Long): Unit
- Классы определений
- AnyRef
- Аннотации
- @throws(classOf[java.lang.InterruptedException]) @native()
© 2002-2019 EPFL, with contributions from Lightbend.
Licensed under the Apache License, Version 2.0.
https://www.scala-lang.org/api/2.13.0/scala-reflect/scala/reflect/api/Constants.html
ЭКСПЕРИМЕНТАЛЬНО
Согласно разделу 6.24 «Выражения констант» спецификации языка Scala, некоторые выражения (называемые выражениями констант) могут быть вычислены компилятором Scala во время компиляции.
Экземпляры scala.reflect.api.Constants#Constant представляют определённые типы таких выражений (с значениями, хранящимися в поле
valueи его сильно типизированными представлениями, называемымиbooleanValue,intValueи т.д.), а именно:Такие константы используются для представления литералов в абстрактных синтаксических деревьях (узел scala.reflect.api.Trees#Literal) и литеральных аргументов для аннотаций файлов классов Java (класс scala.reflect.api.Annotations#LiteralArgument).
Пример
Поле
valueзаслуживает объяснения. Примитивные и строковые значения представляются самими собой, в то время как ссылки на классы и перечисления немного сложнее.Ссылки на классы представлены экземплярами scala.reflect.api.Types#Type (потому что когда компилятор Scala обрабатывает ссылку на класс, подлежащий класс во время выполнения может еще не быть скомпилирован). Для преобразования такой ссылки в класс во время выполнения следует использовать метод
runtimeClassзеркала, такого как scala.reflect.api.Mirrors#RuntimeMirror (простейший способ получить такое зеркало — использовать scala.reflect.runtime.package#currentMirror).Ссылки на значения перечислений представлены экземплярами scala.reflect.api.Symbols#Symbol, которые в JVM указывают на методы, возвращающие основополагающие значения перечислений. Для проверки основного перечисления или получения значения во время выполнения ссылки на перечисление необходимо использовать scala.reflect.api.Mirrors#RuntimeMirror (простейший способ получения такого зеркала — снова scala.reflect.runtime.package#currentMirror).
enum JavaSimpleEnumeration { FOO, BAR } import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface JavaSimpleAnnotation { Class<?> classRef(); JavaSimpleEnumeration enumRef(); } @JavaSimpleAnnotation( classRef = JavaAnnottee.class, enumRef = JavaSimpleEnumeration.BAR ) public class JavaAnnottee {}import scala.reflect.runtime.universe._ import scala.reflect.runtime.{currentMirror => cm} object Test extends App { val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs def jarg(name: String) = jann(TermName(name)).asInstanceOf[LiteralArgument].value val classRef = jarg("classRef").typeValue println(showRaw(classRef)) // TypeRef(ThisType(<empty>), JavaAnnottee, List()) println(cm.runtimeClass(classRef)) // class JavaAnnottee val enumRef = jarg("enumRef").symbolValue println(enumRef) // value BAR val siblings = enumRef.owner.info.decls val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic) println(enumValues) // Scope{ // final val FOO: JavaSimpleEnumeration; // final val BAR: JavaSimpleEnumeration // } // doesn't work because of https://github.com/scala/bug/issues/6459 // val enumValue = mirror.reflectField(enumRef.asTerm).get val enumClass = cm.runtimeClass(enumRef.owner.asClass) val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null) println(enumValue) // BAR }