Как создать экземпляр трейта в универсальном методе в scala?

Я пытаюсь создать экземпляр признака с помощью этого метода

val inst = new Object with MyTrait

Это работает хорошо, но я хотел бы переместить это творение в функцию генератора, т.е.

object Creator {
  def create[T] : T = new Object with T
}

Очевидно, мне понадобится манифест, чтобы как-то исправить проблемы со стиранием типа, но прежде чем я перейду к этому, я задаю 2 вопроса:

  1. Даже с неявным манифестом Scala по-прежнему требует, чтобы T. был признаком. Как мне добавить ограничение на создание [T], чтобы T было признаком?

  2. Если бы я решил использовать метод Class.newInstance для динамического создания экземпляра, а не использовать «новый», как бы мне указать «with» в «новом объекте с T»? Можно ли динамически создавать новые типы бетонных смесей во время выполнения?


person ACyclic    schedule 18.07.2010    source источник


Ответы (2)


Вы не можете этого сделать (даже с манифестом). Код new Object with T включает создание нового анонимного класса, представляющего комбинацию Object with T. Чтобы передать это вашей функции create, вам нужно будет сгенерировать этот новый класс (с новым байт-кодом) во время выполнения, а в Scala нет средств для создания нового класса во время выполнения.

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

Другой возможной стратегией является создание функций преобразования (неявных или иных) в свойства, которые вы хотите использовать с этим классом.

person Ken Bloom    schedule 18.07.2010
comment
Это кажется интересным ограничением языка, но я не вижу причины, по которой его нельзя было исправить с помощью новой поддержки динамического микширования в Scala. Код признака уже доступен в виде статических методов, поэтому поиск линеаризации может быть вычислен во время выполнения, а не встроен в байт-код класса. Тогда вам просто нужно добавить проверку типа во время выполнения, чтобы InstanceOf работал. - person ACyclic; 18.07.2010

Я не уверен, какова мотивация вашего вопроса, но вы можете рассмотреть возможность передачи фабрики для T в качестве неявного параметра. Это называется использованием классов типов или специального полиморфизма.

object Test extends Application {
  trait Factory[T] {
    def apply: T
  }
  object Factory {
    /**
     * Construct a factory for type `T` that creates a new instance by
     * invoking the by-name parameter `t`
     */
    def apply[T](t: => T): Factory[T] = new Factory[T] {
      def apply = t
    }
  }

  // define a few traits...
  trait T1
  trait T2

  // ...and corresponding instances of the `Factory` type class.
  implicit val T1Factory: Factory[T1] = Factory(new T1{})
  implicit val T2Factory: Factory[T2] = Factory(new T2{})

  // Use a context bound to restrict type parameter T
  // by requiring an implicit parameter of type `Factory[T]`
  def create[T: Factory]: T = implicitly[Factory[T]].apply

  create[T1]
  create[T2]

}

На другом конце спектра вы можете вызывать компилятор во время выполнения, как подробно описано в этот ответ на вопрос« Динамическое микширование в Scala - возможно ли? ».

person retronym    schedule 18.07.2010
comment
Спасибо, возможно, мне придется воспользоваться этим методом. Мой вариант использования - прокси-сервер Java. Я хочу написать удаленную библиотеку. Поэтому мне нужно определить интерфейсы для всех моих классов, а это неприятно, поскольку я хочу все раскрыть. Одно из решений - написать все как трейт, и тогда я получу определение интерфейса бесплатно. Назначение функции create - создать экземпляр признака на конкретной стороне прокси-соединения. - person ACyclic; 18.07.2010