Вот пример простого API, который использует эффект ZIO для возврата None или Option[String]. Я использую расписание ZIO для запуска эффекта, пока возвращается None, но ограничено определенным количеством раз. Пример основан на коде из ZIO usecases_scheduling:

import zio._
import zio.random._
import zio.duration._
import zio.console.{Console, putStrLn}
import zio.Schedule

import scala.util.{Random => ScalaUtilRandom}

object RecordAPI {

  def randomId(length: Int): String =
    LazyList.continually(ScalaUtilRandom.nextPrintableChar).filter(_.isLetterOrDigit).take(length).mkString

  def getRecordId: Task[Option[String]] = Task.effect(
    if (ScalaUtilRandom.nextInt(10) >= 7) Some(randomId(16)) else None
  )
}

object ScheduleUtil {

  def schedule[A]: Schedule[Random, Option[String], Option[String]] =
    (Schedule.exponential(10.milliseconds) && Schedule.recurs(10)) *> Schedule.recurWhile(_.isEmpty)
}

object RandomScheduler extends scala.App {
  implicit val rt: Runtime[zio.ZEnv] = Runtime.default

  rt.unsafeRun {
    RecordAPI.getRecordId
      .repeat(ScheduleUtil.schedule)
      .foldM(
        ex => putStrLn(s"failed with ${ex.getMessage}"),
        success => putStrLn(s"Succeeded with $success")
      )
  }
}

Этот эффект ниже имеет тип ZIO[Random with clock.Clock, Throwable, Option[String]]:

RecordAPI.getRecordId.repeat(ScheduleUtil.schedule)

Я хотел бы удалить зависимость ScheduleUtil.schedule от Random, предоставив env Random и получив эффект ZIO[Any with clock.Clock, Throwable, Option[String]]:

RecordAPI.getRecordId.repeat(ScheduleUtil.schedule.provide(Random))

Но я получаю ошибку компиляции:

[error]  found   : zio.random.Random.type
[error]  required: zio.random.Random
[error]     (which expands to)  zio.Has[zio.random.Random.Service]
[error]       .repeat(ScheduleUtil.schedule.provide(Random))
[error]                                             ^
[error] one error found

Какой параметр следует предоставить методу .provide?

2
Valentine 30 Ноя 2020 в 23:32

1 ответ

Лучший ответ

В сообщении об ошибке говорится, что вы пытаетесь передать функцию provide Random.type в соответствии:

RecordAPI.getRecordId.repeat(ScheduleUtil.schedule.provide(Random))

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

val hasRandomService: Random = Has.apply(Random.Service.live)
val randomIdZIO: ZIO[Random, Throwable, Option[String]] = 
  RecordAPI.getRecordId.repeat(ScheduleUtil.schedule.provide(hasRandomService))

Но если вы хотите избавиться от ScheduleUtil.schedule, возможно, лучше использовать функцию Schedule.fromFunction:

val randomIdZIOFromFunction: ZIO[Random, Throwable, Option[String]] = 
  RecordAPI.getRecordId.repeat(
    Schedule.fromFunction(_ => if (ScalaUtilRandom.nextInt(10) >= 7) Some(randomId(16)) else None)
)
1
Boris Azanov 1 Дек 2020 в 08:41