scala的通用对象加载函数

时间:2010-03-12 15:04:58

标签: generics scala manifest scala-2.8 parameterization

我开始使用后端使用Hibernate(JPA)的Scala应用程序。为了加载一个对象,我使用这行代码:

val addr = s.load(classOf[Address], addr_id).asInstanceOf[Address];

毋庸置疑,这有点痛苦。我写了一个帮助类,看起来像这样:

import org.hibernate.Session

class DataLoader(s: Session) {
  def loadAddress(id: Long): Address = {
    return s.load(classOf[Address], id).asInstanceOf[Address];
  }
  ...
}

所以,现在我可以这样做:

val dl = new DataLoader(s)
val addr = dl loadAddress(addr_id)

以下是问题:如何编写可以使用相同模式加载任何对象的通用参数化方法?即

val addr = dl load[Address](addr_id)

(或沿着这些方向的东西。)

我是Scala的新手所以请原谅任何特别可怕的东西。

2 个答案:

答案 0 :(得分:5)

这是:

import org.hibernate.Session
class DataLoader(s: Session) {
  def load[A](id: Long)(implicit m: Manifest[A]): A = {
    return s.load(m.erasure, id).asInstanceOf[A];
  }
}

编辑 - 或者,确保任何播放错误 - 由于hibernate返回错误的对象 - 将在load内发生,如下所示:

import org.hibernate.Session
class DataLoader(s: Session) {
  def load[A](id: Long)(implicit m: Manifest[A]): A = {
    return m.erasure.asInstanceOf[Class[A]].cast(s.load(m.erasure, id));
  }
}

在Scala 2.8上你也可以这样写:

import org.hibernate.Session
class DataLoader(s: Session) {
  def load[A : Manifest](id: Long): A = {
    return s.load(manifest[A].erasure, id).asInstanceOf[A];
  }
}

您也可以将其与隐式会话结合使用,如Chris所示:

def load[A](id: Long)(implicit m: Manifest[A], s: org.hibernate.Session): A = {
  return s.load(m.erasure, id).asInstanceOf[A];
}

请注意,您无法将上下文视图表示法(A : Manifest)与其他隐式参数组合使用。

答案 1 :(得分:3)

一种方法是利用java.lang.Class.cast方法来执行以下操作:

def load[A](clazz: Class[A], id: Long)(implicit s: Session) : A 
       = clazz.cast(s.load(clazz, id))

然后用法如下:

implicit val s = ...//get hibernate session
val addr = load(classOf[Address], 1)

它与你已经没有什么不同,但为了访问class实例,你需要传入它。

我非常有信心你不能安全Manifests做你想做的事情,因为他们无法在编译时提供参数化Class[Address]为了使演员工作所需的时间(他们只能提供Class[_]删除)。我没有看到任何其他机制来从Manifest

进行演员表

您当然可以使用asInstanceOf[A]而不是cast,但这会在编译时被删除到isInstanceOf[Object],因此在编译时类型检查方面无用(因此不可取) )。