Как я могу вызвать конструктор абстрактного типа Scala? - PullRequest
8 голосов
/ 01 октября 2011

Я пытаюсь выяснить, как вызвать конструктор для абстрактного типа Scala:

class Journey(val length: Int)
class PlaneJourney(length: Int) extends Journey(length)
class BoatJourney(length: Int) extends Journey(length)

class Port[J <: Journey] {
  def startJourney: J = {
    new J(23) // error: class type required but J found
  }
}

Это вообще возможно? Я знаком с манифестами Scala , но мне не ясно, как они могли бы здесь помочь. Также я не могу понять, как сделать то же самое с конструктором apply () объекта-компаньона:

object Journey { def apply() = new Journey(0) }
object PlaneJourney { def apply() = new PlaneJourney(0) }
object BoatJourney { def apply() = new BoatJourney(0) }

class Port[J <: Journey] {
  def startJourney: J = {
    J() // error: not found: value J
  }
}

Любые мысли с благодарностью приняты!

Ответы [ 3 ]

7 голосов
/ 01 октября 2011

Вашему классу нужен неявный параметр конструктора, чтобы получить Manifest. Затем вы можете вызвать erasure, чтобы получить Class и вызвать newInstance, который рефлексивно вызывает нулевой конструктор, если он есть.

class J[A](implicit m:Manifest[A]) {
  def n = m.erasure.newInstance()
}

new J[Object].n

Начиная с версии Scala 2.10, свойство erasure в манифесте устарело. def n = m.runtimeClass.newInstance() делает то же самое, но без предупреждений.

7 голосов
/ 01 октября 2011

Нет прямого способа вызвать конструктор или получить доступ к объекту-компаньону только по типу. Одним из решений будет использование класса типов, который создает экземпляр по умолчанию данного типа.

trait Default[A] { def default: A }

class Journey(val length: Int)
object Journey {
  // Provide the implicit in the companion
  implicit def default: Default[Journey] = new Default[Journey] {
    def default = new Journey(0)
  }
}

class Port[J <: Journey : Default] {
  // use the Default[J] instance to create the instance
  def startJourney: J = implicitly[Default[J]].default
}

Вам нужно будет добавить неявное определение Default ко всем сопутствующим объектам классов, которые поддерживают создание экземпляра по умолчанию.

0 голосов
/ 01 октября 2011

Я склоняюсь к тому, что это невозможно сделать.Я далёк от гуру Scala, но мои рассуждения таковы:

  1. У вас есть класс Port с аргументом типа T, где T должен наследовать от Journey (но T не обязательно должен быть в точности Путешествие, это важно).
  2. В Port вы определяете метод, который создает новый T. Этот класс понятия не имеет, что такое T, и, следовательно, как выглядит конструктор T.
  3. Поскольку вы не знаете, какие аргументы принимает конструктор T, вы не знаете, какие аргументы передать ему.

Решения этой проблемы очень хорошо обрабатываются в другом вопросе, поэтомуЯ укажу вам их, а не повторю здесь: Абстрактные типы / Параметры типов в Scala

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...