избегайте передачи избыточных параметров

#kotlin

Вопрос:

Я использую Kotlin с Spring Webflux.

У меня есть две функции, которые извлекают некоторые данные из запроса, делают извлеченные данные доступными для следующей функции.

Пример содержит только две функции, но у меня их дюжина.

 suspend fun extractQueryParam1(serverRequest: ServerRequest,
                               fn: (p1: String) -> ServerResponse): ServerResponse =
    serverRequest.queryParamOrNull("p1")
        ?.let(fn)
        ?: badRequestResponse("Missing p1")

suspend fun extractQueryParam2(serverRequest: ServerRequest,
                               fn: (p1: Long) -> ServerResponse): ServerResponse =
    serverRequest.queryParamOrNull("p2")
        ?.toLong()
        ?.let(fn)
        ?: badRequestResponse("Missing p2")
 

Использование

     extractQueryParam1(req) { p1 ->
        extractQueryParam2(req) { p2 ->

        }
    }
 

Это как req -то похоже на контекст для этих функций, и они используют один и тот же контекст.

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

Возможно ли это в Kotlin? Как?

Я вдохновил себя на использование HTTP Akka с точки зрения использования. Они добились этого с помощью директив, но я туда еще не ходил… пока.

Вот пример: https://doc.akka.io/docs/akka-http/current/routing-dsl/routes.html#route-seal-method-to-modify-httpresponse

Ответ №1:

Превратите их в функции расширения, а затем вы можете использовать with run области или для вызова ряда из них без повторной передачи параметра.

 suspend fun ServerRequest.extractQueryParam1(
                               fn: (p1: String) -> ServerResponse): ServerResponse =
    queryParamOrNull("p1")
        ?.let(fn)
        ?: badRequestResponse("Missing p1")

suspend fun ServerRequest.extractQueryParam2(
                               fn: (p1: Long) -> ServerResponse): ServerResponse =
    queryParamOrNull("p2")
        ?.toLong()
        ?.let(fn)
        ?: badRequestResponse("Missing p2")
 

Использование:

 with(req) {
    extractQueryParam1 { p1 ->
        extractQueryParam2 { p2 ->

        }
    }
}
 

Поскольку вы создаете DSL, вместо with или run , возможно, вам захочется написать свою собственную функцию области, которая создает запрос, а затем запускает код в его лямбда, используя запрос на сборку в качестве получателя.

Комментарии:

1. Не могли бы вы, пожалуйста, подробнее остановиться на последнем варианте?

2. Возможно, в вашем DSL должен быть внешний элемент, который создает запрос. Функция более высокого порядка, представляющая этот элемент, может принимать лямбда-код с получателем запроса. Затем, когда вы используете его, он будет похож на использование with(req) , за исключением того, что он будет частью вашего DSL. Я не знаю, имеет ли это смысл с тем, что вы делаете, так как я никогда не использовал Весну.