Как найти тип значения, которое было неявно преобразовано?

Я пытаюсь вытащить следующий код из класса в трейт для повторного использования:

import org.slf4j.{LoggerFactory, Logger}
import slick.driver.H2Driver.api._

import scala.concurrent.Await
import scala.concurrent.duration.Duration


object UserProfileFixtures {
  val logger: Logger = LoggerFactory.getLogger(UserProfileFixtures.getClass)

  val table = UserProfileQueries.query

  // todo: Create a trait for all this
  def createSchema(db: Database) = {

    logger.info("Creating schema for the UserProfiles table")
    Await.result(db.run((table.schema).create), Duration.Inf)
    logger.info("UserProfiles table schema created")
  }
}

Проблема в том, что table неявно преобразуется во что-то, что добавляет свойство schema. Если я просто подниму и сдвину приведенное выше, неявное преобразование table не произойдет, и компилятор не сможет найти свойство schema.

Как я могу узнать, какой тип я должен дать table в следующем трейте?

import org.slf4j.Logger
import slick.driver.H2Driver.api._

import scala.concurrent.Await
import scala.concurrent.duration.Duration


trait FixtureHelper {

  val logger: Logger
  val data: Seq
  val table: TableQuery[_]     // this type is wrong...

  def createSchema(db: Database) = {

    logger.info("Creating schema")
    // compiler can't resolve `schema` in the line below
    Await.result(db.run(table.schema.create), Duration.Inf)
    logger.info("Schema created")
  }
}

Я использую slick 3.0 BTW, но это не должно иметь значения. Я хочу знать, как узнать тип значения после его неявного преобразования.


person jbrown    schedule 29.03.2015    source источник


Ответы (1)


Вы можете использовать структурные типы, чтобы получить результирующий неявный класс:

scala> implicit class RchStr(s: String) { def v = 0 }
defined class RchStr

scala> implicitly[{def v: Int}]("aaa")
res5: AnyRef{def v: Int} = RchStr@3ab71d5e //"RchStr" is implicitly inferred type here

scala> implicitly[{def v: Any}]("aaa")
res6: AnyRef{def v: Any} = RchStr@2de743a3 // you may not know type of `v` - just specify `Any` then

scala> implicitly[{def z: Any}]("aaa") //there is no implicit conversions to something which has `z` member
<console>:9: error: type mismatch;
 found   : String("aaa")
 required: AnyRef{def z: Any}
              implicitly[{def z: Any}]("aaa")
                                       ^

Здесь мне потребовалось некоторое неявное преобразование для чего-либо с помощью метода {def v: Int}. В вашем конкретном случае это должно быть что-то вроде:

println(implicitly[{def schema: Any}](table).getClass())

Если вам нужно узнать исходный тип table, вы можете просто использовать table.getClass или проверить scaladoc на наличие неявно выведенного типа table для неявных преобразований.

Также IntelliJ IDEA показывает вам (Cntrl + наведение мыши) предполагаемый тип явно. Вам также может понадобиться проверить некоторые супертипы предполагаемого типа.

Также может быть полезно: Отображение предполагаемых типов выражений Scala, Выведенный тип в программе Scala

Это даст вам тег типа для точного типа, который можно неявно преобразовать во что-то с помощью schema:

import scala.reflect.runtime.universe._
def typeOf[T](x:T)( implicit tag: TypeTag[T], conversion: T => {def schema: Any} ) = tag
println(typeOf(table))
person dk14    schedule 29.03.2015
comment
Хорошо, это дает мне: slick.profile.RelationalProfile$TableQueryExtensionMethods. Извините, что я полный любитель, но какой тип мне нужно дать «таблице», чтобы это сработало? Я пытался заменить знак $ точкой и использовать квадратные скобки, но Intellij все равно не решит эту проблему. - person jbrown; 29.03.2015
comment
Итак, я знаю, что должен сделать table типа slick.profile.RelationalProfile$TableQueryExtensionMethods, но каков синтаксис? Кажется, я не могу ссылаться на вложенный класс. - person jbrown; 29.03.2015
comment
О, мне нужно заменить $ на #. - person jbrown; 29.03.2015
comment
... и теперь он не может найти свойство create table.schema :-( Я начну новый вопрос. - person jbrown; 29.03.2015