Scala reflection and Squeryl

本秂侑毒 提交于 2020-01-03 02:27:29

问题


I'm working on my first substantial project using Scala, Scalatra, and Squeryl, and happened upon the following problem: I wanted to have an abstract base class for my DAOs that provided a simple implementation of the basic CRUD operations (create, read, update, delete), so I needed a way for said abstract base class to be aware of which table to reference.

With Squeryl, you map your data classes to actual tables in a singleton object that extends squeryl.Schema, and your DAOs are generally companion objects for each class.

I came up with the following solution using type tags:

First, an excerpt of the base class from which all DAOs will inherit (Note: DBRecord is a sub of Squeryl's KeyedEntity):

abstract class CrudOps[S <: DBRecord](implicit tt: TypeTag[S]) {

  def create(item: S)= {
    inTransaction{
      val result = ATSchema.recordTable.insert(item)
    }
  }

Next, the recordTable function in ATSchema:

object ATSchema extends Schema {
  val users = table[User]
  def recordTable[T <: DBRecord](implicit tt: TypeTag[T]): Table[T] = tt.tpe match {
    case t if t =:= typeOf[User] => users.asInstanceOf[Table[T]]
    //...other table types go here
    case _ => throw new IllegalArgumentException("Unknown DBRecord type")
  }
}

Now, this works, I have several tables and CrudOps grabs the right one and does its stuff. But there's something I'm not understanding (I'm still fairly new to Scala): Why do I need to cast my table vals in recordTable() to Table[T]? If I remove the .asInstanceOf, I get a type mismatch, but users is of the type Table[User]... seems like it ought to be unnecessary. Also, this has the feel of a complicated solution to what should be a trivial problem (maybe I'm abusing the type system), and also couples CrudOps to the Schema (which I would like to avoid), so I am certainly open to suggestions from folks with more Scala and/or Squeryl experience than I :)


回答1:


It's not really a Squeryl thing. As I understand it, the problem is that the pattern match testing is done at runtime, after type erasure has occurred. Scala is able to keep the type information around with the TypeTag and perform the runtime check but it can't infer that the types are correct at compile time. If you were to try something like

case t: ClassTag[User] => users

Which is asking the compiler to do a static check, you would get a warning that the User type is erased. The way you are doing it should work since it should be fine to perform the cast after you've verified the type, and I don't think there is a better way.



来源:https://stackoverflow.com/questions/18407145/scala-reflection-and-squeryl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!