Универсальная функция загрузки объекта для scala - PullRequest
4 голосов
/ 12 марта 2010

Я запускаю приложение Scala, которое использует Hibernate (JPA) на заднем плане. Чтобы загрузить объект, я использую эту строку кода:

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)

Вот вопрос: Как мне написать универсальный параметризованный метод, который может загружать любой объект, используя этот же шаблон? * 1012 т.е. *

val addr = dl load[Address](addr_id)

(или что-то в этом роде.)

Я новичок в Scala, поэтому, пожалуйста, прости все, что особенно отвратительно.

Ответы [ 2 ]

5 голосов
/ 12 марта 2010

Вот оно:

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];
  }
}

РЕДАКТИРОВАТЬ - Или, чтобы гарантировать, что любая ошибка приведения - в результате возврата из спящего режима неверного объекта - будет происходить внутри 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];
  }
}

Вы также можете комбинировать его с неявным сеансом, как это предлагает Крис :

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

Обратите внимание, что вы не можете комбинировать нотацию контекстного представления (A : Manifest) с дополнительными неявными параметрами.

3 голосов
/ 12 марта 2010

Один из методов состоит в том, чтобы воспользоваться преимуществом метода 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] и поэтому бесполезно с точки зрения проверки типов во время компиляции (и, следовательно, не рекомендуется).

...