Рассматривать конструктор как функцию в Scala - как разместить конструкторы на карте? - PullRequest
10 голосов
/ 29 мая 2011

Мне нужно разобрать некоторые сообщения. Первые 4 байта сообщения идентифицируют тип сообщения, поэтому, используя это, я могу создать экземпляр объекта подходящего типа. Чтобы сделать это эффективной операцией, я подумал, что создам хеш-карту, в которой ключом являются первые 4 байта, а значением является конструктор объекта. Я могу просто посмотреть на конструктор и вызвать его.

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

Чтобы получить конкретику на упрощенном примере, предположим, что у нас есть базовый класс сообщений MsgBase и пара подклассов MsgA и MsgB. Если я создаю объект-компаньон для каждого из сообщений и помещаю в него фабричную функцию, я могу без проблем создать массив, используя эти функции.

Вот упрощенный пример, который принимает сообщение в виде строки.

class MsgBase(message: String) { }

class MsgA(message: String) extends MsgBase(message) { }

object MsgA  { def makeIt(message: String): MsgA = new MsgA(message)  }

и где MsgB аналогично. Тогда я могу сделать карту:

val cm = Map[String, (String) => MsgBase]("a" -> MsgA.makeIt, "b" -> MsgB.makeIt)

val myMsg = cm("a")("a.This is the message")

Кажется, я должен иметь возможность ссылаться на конструктор объекта сообщения непосредственно в выражении, строящем карту, а не использовать тривиальную функцию в объекте-компаньоне, но я не нашел никакого способа выразить это. Есть ли способ?

Ответы [ 3 ]

14 голосов
/ 29 мая 2011

Попробуйте

"a" -> (new MsgA(_))

(необходимы все скобки).

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

"a" -> ( (s: String) => new MsgA(s) )
3 голосов
/ 30 мая 2011

Для этого случая было бы лучше использовать case-классы, которые автоматически предоставляют вам функции для создания новых объектов.

scala> case class MsgA(message: String) extends MsgBase(message)
scala> case class MsgB(message: String) extends MsgBase(message)

Таким образом, вы можете ссылаться на них только по имени, без каких-либо синтаксических издержек

scala> val m = Map("a"->MsgA, "b"->MsgB)
m: scala.collection.immutable.Map[java.lang.String,scala.runtime.AbstractFunction1[java.lang.String,Product with MsgBase]] = Map((a,<function1>), (b,<function1>))

scala> m("a")("qqq")                              
res1: Product with MsgBase = MsgA(qqq)

В качестве альтернативного подхода вы можете вручную создать сопутствующий объект с переопределенным методом apply. Подробнее см. Программирование scala, глава 6

2 голосов
/ 29 мая 2011
val cm = Map[String, (String) => MsgBase]("a" -> (new MsgA(_)), "b" -> (new MsgB(_)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...