Я подозреваю, что вы не понимаете, как implicit
используется в Scala. Существует несколько популярных способов использования , и одним из них является использование имплицитов для передачи некоторой "контекстной" информации. Код, на который вы смотрите, является классическим примером такого использования.
Когда вы делаете «тайм-аут», вам нужно выбрать две вещи:
- где (в каком потоке) основное задание будет выполняться на
- где (в каком потоке) будет запущен таймер, поскольку в мире JVM (в отличие от JavaScript, например) нет стандартного таймера.
Важным в этих параметрах является то, что, с одной стороны, они важны для работы, но, с другой стороны, они поддерживают только основной параметр. Другое дело, что вы, вероятно, хотите иметь только один (или очень мало) глобальных объектов, которые вы используете повсюду для этих целей. Это то, что делает их контекстом, и поэтому они передаются неявно.
Теперь у вас есть выбор, где их взять:
- также сделайте их своим контекстом, то есть заставьте звонящего передать их вам (также неявно
- создайте свои собственные экземпляры
Этот выбор не является тривиальным дизайнерским решением и зависит от того, как вы собираетесь использовать свой API. Как правило, правильный выбор - первый - сделайте их своим контекстом. Таким образом, вы позволяете вызывающей стороне устанавливать контекст так, как он хочет (например, должны ли Timer
и Concurrent
использовать один и тот же пул потоков или разные?). Иногда это нормально, чтобы создать свой собственный независимый контекст. Или обернуть другой контекст, который вы получили извне, во что-то конкретное для вас.
Предполагая, что вы хотите обернуть внешний контекст на границе вашего Http4sApi
, вы можете написать код, подобный следующему:
final case class Http4sApi()(implicit executionContext: ExecutionContext) extends HttpApiAlg[IO] {
// create IO-specific context from the executionContext
private implicit val cs = IO.contextShift(executionContext)
private implicit val timer = IO.timer(executionContext)
Тогда вы можете написать просто
def withTimeout(timeout: Duration)(service: HttpService[IO]): HttpService[IO] = timeout match {
case finite: FiniteDuration => Timeout(finite)(service)
case _ => service
}
и он должен скомпилироваться.