À quoi fait référence le service avec état dans ce cas?
Voulez-vous dire qu'il exécutera un effet secondaire lorsqu'un objet est construit?
Pour cela, une meilleure idée serait d'avoir une méthode qui exécute l'effet secondaire au démarrage de votre application. Au lieu de l'exécuter pendant la construction.
Ou peut-être que vous dites qu'il détient un état mutable à l'intérieur du service? Tant que l'état mutable interne n'est pas exposé, il devrait être correct. Il vous suffit de fournir une méthode pure (référentiellement transparente) pour communiquer avec le service.
Pour développer mon deuxième point:
Disons que nous construisons une base de données en mémoire.
class InMemoryDB(private val hashMap: ConcurrentHashMap[String, String]) {
def getId(s: String): IO[String] = ???
def setId(s: String): IO[Unit] = ???
}
object InMemoryDB {
def apply(hashMap: ConcurrentHashMap[String, String]) = new InMemoryDB(hashMap)
}
OMI, cela n'a pas besoin d'être efficace, car la même chose se produit si vous effectuez un appel réseau. Cependant, vous devez vous assurer qu'il n'y a qu'une seule instance de cette classe.
Si vous utilisez l' Ref
effet chats, ce que je ferais normalement, c'est flatMap
la référence au point d'entrée, donc votre classe n'a pas besoin d'être efficace.
object Effectful extends IOApp {
class InMemoryDB(storage: Ref[IO, Map[String, String]]) {
def getId(s: String): IO[String] = ???
def setId(s: String): IO[Unit] = ???
}
override def run(args: List[String]): IO[ExitCode] = {
for {
storage <- Ref.of[IO, Map[String, String]](Map.empty[String, String])
_ = app(storage)
} yield ExitCode.Success
}
def app(storage: Ref[IO, Map[String, String]]): InMemoryDB = {
new InMemoryDB(storage)
}
}
OTOH, si vous écrivez un service partagé ou une bibliothèque qui dépend d'un objet avec état (disons plusieurs primitives de concurrence) et que vous ne voulez pas que vos utilisateurs se soucient de quoi initialiser.
Ensuite, oui, il doit être enveloppé dans un effet. Vous pouvez utiliser quelque chose comme, Resource[F, MyStatefulService]
pour vous assurer que tout est bien fermé. Ou juste F[MyStatefulService]
s'il n'y a rien à fermer.
delay
et renvoyer un F [Service] . A titre d'exemple, voir lastart
méthode sur IO , elle renvoie une IO [Fibre [IO,?]] , Au lieu de la fibre ordinaire .