Можно ли вызвать функцию общего типа, передав класс, указанный на карте? - PullRequest
0 голосов
/ 19 декабря 2018

Спрашиваю здесь, потому что я вырываю свои волосы, пытаясь понять, что именно мне нужно сделать здесь.

Я пишу конечную точку пакетной обработки, которая пытается преобразовать телозапрос к конкретному классу дел Scala перед выполнением логики в самой конечной точке.

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

def executeWithType[A](action: () => Action[A], batchRequest: BatchRequest): Future[Result] = {
    action()(request.map(_ => batchRequest.body.map(_.as[A]).get))
}

Затем у меня есть некоторый код, который проверяет, какую конечную точку вызывать и к какому типу приводить в зависимости от того, что находится в самом BatchRequest.

val res: Future[Result] = (batchRequest.method, batchRequest.endpoint) match {
    case ("POST", "/endpoint1") => {
        executeWithType[EndpointOneType](controller.endpointOne _, batchRequest)
    }
    case ("POST", "/endpoint2") => {
        executeWithType[EndpointTwoType](controller.endpointTwo _, batchRequest)
    }
    case _ => Future.successful(NotFound)
}

Вышеописанное прекрасно работает - однако я хочу, если возможно, избежать подобного кортежа с отдельными случаями и указать карту, которая делает это вместо этого.В моем идеальном мире конечный результат блока кода, приведенного выше, выглядел бы так:

val actions = Map(
    Seq("POST", "/endpoint1") -> (controller.endpointOne _, EndpointOneType),
    Seq("POST", "/endpoint2") -> (controller.endpointTwo _, EndpointTwoType)
)

val res = actions.get(Seq(batchRequest.method, batchRequest.endpoint)) match {
    case Some(action) => {
         executeWithType[action._2](action._1, batchRequest)
    }
    case _ => Future.successful(NotFound)
}

Возможно ли это вообще?Я пытался бороться с этим, но мое понимание отражения в Scala очень слабое, поэтому я не совсем уверен, как мне поступить.Я пробовал кучу вещей classOf и typeTag и Class [_], но я в основном раскачиваюсь в темноте.Надеясь на то, что кто-то более знающий, чем я, может помочь мне.

Важные вещи:

  1. Что должно идти во втором пространстве кортежа в значении Карты?Как передать переменную Class?
  2. Как использовать переменную class-as-a-variable для вызова метода общего типа?

1 Ответ

0 голосов
/ 19 декабря 2018

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

Вы не можете.Но я хотел бы предложить альтернативное решение.

Просто определите локальный класс вместо кортежей:

class RequestAction[A](action: () => Action[A]) {
  def apply(request: BatchRequest) = executeWithType(action, request)
}

val actions = Map(
    Seq("POST", "/endpoint1") -> new RequestAction(controller.endpointOne _), // type parameter is inferred
    Seq("POST", "/endpoint2") -> new RequestAction(controller.endpointTwo _)
)

val res = actions.get(Seq(batchRequest.method, batchRequest.endpoint)) match {
    case Some(action) => action(batchRequest)
    case _ => Future.successful(NotFound)
}

(хотя это зависит от кода, не показанного в вопросе, это выглядит вероятнымчто вы можете упростить, передав Action[A] вместо () => Action[A]).

...