Как сравнить возвращаемый тип метода с родным Scala или TypeTag?

Итак, я использую библиотеку отражений Scala и пытаюсь проверить, соответствует ли метод заданному типу. Чтобы упростить, я пытаюсь проверить только его вывод.

Что у меня есть сейчас:

val returnType = methodSymbol.returnType
// returnType: reflect.runtime.universe.Type = java.lang.String

Итак, я могу прочитать, что это строка, но она имеет ужасный тип reflect.runtime.universe.Type. Как я могу сравнить проверку, если этот возвращаемый тип является простой строкой? Я даже пытался использовать TypeTags, которые достаточно просты, но преобразование Type в TypeTag требует таких монументальных усилий, что я не верю, что такую ​​простую задачу нельзя решить проще.

Итак, как я могу сравнить это со строкой и просто получить логическое значение? Я думал просто вызвать toString() и попытаться проанализировать его обратно в нормальный тип, но это было бы действительно отвратительно делать в коде, IMO. Кроме того, я не могу просто указать имя метода, потому что я работаю над списком методов, и позже будет больше.

Я видел несколько вопросов и даже этот (на мой взгляд, абсурдно сложный) ответ о том, как преобразовать тип в TypeTag, но, опять же, меня сбивает с толку уровень сложности такой тривиальной задачи. Я уже подумываю вырвать свои редкие волосы. Помощь приветствуется.

РЕДАКТИРОВАТЬ: мне удалось провести сравнение для самой строки, но не для метода, возвращающего строку.

Чтобы сравнить возвращаемый тип String, я делаю:

val returnType = methodSymbol.returnType
returnType =:= typeTag[String].tpe

Однако, когда я пытаюсь проверить это с помощью наследования и метода, используя <:<, это не сработает. Чтобы уточнить, B расширяет черту A, сигнатура типа () => B, но я не могу сопоставить при кодировании

val typeSig = methodSymbol.typeSig
typeSig <:< typeTag[() => A].tpe

person Lucas Lima    schedule 11.06.2020    source источник
comment
Зачем вам нужно проверять возвращаемый тип метода по строке? В Scala рефлексия обычно не приветствуется, поэтому неудивительно, что простые вещи трудно делать.   -  person Luis Miguel Mejía Suárez    schedule 12.06.2020
comment
Почему бы просто не сделать returnType == typeOf[String]?   -  person user    schedule 12.06.2020
comment
Ну, мне не нужно проверять строку. Мне нужно убедиться, что некоторые методы в данном объекте соответствуют ожидаемому шаблону - я хочу, чтобы они не принимали аргументы в качестве входных данных и возвращали заданный тип. Строка — простой пример. Я не могу сравнивать непосредственно с typeTag, потому что это сравнение просто не работает, учитывая, что returnType не является TypeTag, как было сказано ранее.   -  person Lucas Lima    schedule 12.06.2020
comment
typeOf возвращает Type, а не TypeTag, насколько мне известно. Посмотрите эту игровую площадку Scastie: scastie.scala-lang.org/sQDO2hDJThyKuUiWaZWRmQ   -  person user    schedule 12.06.2020
comment
Мне жаль. Я неправильно понял - хотя вы говорили о typeTag. Виноват. Во всяком случае, я попытался это сделать, и он выдал забавное `found: ru.Type/required: Reflect.runtime.universe.Type`. Используя typeTag и преобразовав его в тип, теперь он работает, хотя и не соответствует наследованию.   -  person Lucas Lima    schedule 12.06.2020
comment
Это странно. ru является scala.reflect.runtime.universe   -  person user    schedule 12.06.2020
comment
Я согласен. Я даже не пытался понять, потому что это не имело для меня смысла. Использование typeTag сработало частично, так что я в порядке   -  person Lucas Lima    schedule 12.06.2020
comment
Будет ли отражение Java достаточным для вашего варианта использования? Это намного проще в использовании.   -  person Seth Tisue    schedule 12.06.2020
comment
Ну, не совсем, но я могу смешать и то, и другое (я уже так делаю, если честно), и получить оттуда то, что мне нужно.   -  person Lucas Lima    schedule 12.06.2020
comment
@LucasLima, если returnType равно B, почему вы проверяете returnType <:< typeTag[() => B].tpe (то есть returnType <:< typeOf[() => B])? Это не может быть правдой.   -  person Dmytro Mitin    schedule 12.06.2020
comment
Потому что я тупой и неправильно написал. Собираюсь исправить.   -  person Lucas Lima    schedule 12.06.2020
comment
@LucasLima returnType <:< typeOf[() => A] возвращает true scastie.scala-lang.org/4q5BilFTSQCSw3UTkufvxQ   -  person Dmytro Mitin    schedule 12.06.2020
comment
@LucasLima, если для вас returnType <:< typeOf[() => A] дает false, вы должны предоставить более подробную информацию о том, как воспроизвести ваше поведение (напишите весь код).   -  person Dmytro Mitin    schedule 12.06.2020
comment
@LucasLima Если returnType получено из MethodSymbol, то returnType <:< typeOf[() => A] все равно возвращает true scastie.scala-lang.org/UQBTG9ytTv2Pgwn8RxlVEw   -  person Dmytro Mitin    schedule 12.06.2020
comment
Это было заблуждением с моей стороны. Я предполагал, что returnType и typeSignature будут возвращать объекты одного и того же типа - это неверно. Действительно, с returnType работает нормально. Я исправлю вопрос (еще раз) и приму ваш ответ.   -  person Lucas Lima    schedule 12.06.2020


Ответы (2)


Если вы хотите работать с типами как String, вы должны их разобрать

import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox

val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val str = "java.lang.String"
val tpe: Type = (tb.typecheck(tb.parse(s"type T = $str"), mode = tb.TYPEmode) match {
  case q"type T = $typ" => typ
}).tpe // String
tpe =:= typeOf[String] //true

(Я хотел бы сделать только tb.typecheck(tb.parse(str/*, mode = ???*/), mode = tb.TYPEmode).tpe, но не могу найти, как вызывать TypeParser вместо TermParser с отражением во время выполнения, это соответствует разнице между tq"..." и q"...", иначе я получаю компаньон String вместо самого String. Конечно, tq"$str" тоже дает неправильный тип, потому что это макрос, он может работать только для литералов времени компиляции: tq"java.lang.String".)

person Dmytro Mitin    schedule 11.06.2020

Возможно, это не совсем то, о чем вы просите, но вы можете использовать java.lang.reflect в Scala.

import java.lang.reflect.Method

class C {
  def doSomething(): String = {
    return "hello"
  }
  def doSomethingElse(): String = {
    return "bye"
  }
  def doNothing(): Int = {
    return 190
  }
}

val doSomethingMethod: Method = classOf[C].getMethods()(2)
val doNothingMethod: Method = classOf[C].getMethods()(1)
val doSomethingElseMethod: Method = classOf[C].getMethods()(0)

// false
doSomethingMethod.getReturnType.equals(doNothingMethod.getReturnType)

// true
doSomethingMethod.getReturnType.equals(doSomethingMethod.getReturnType)

// you can compare the simple name, too, if that's easier
println(s"'${doSomethingMethod.getReturnType.getSimpleName}'")
// 'String'
person ELinda    schedule 11.06.2020