4 votes

Erreur de type dans la méthode asynchrone

J'ai une méthode asynchrone que j'écris et qui est censée interroger de manière asynchrone un port jusqu'à en trouver un, ou atteindre le délai de 5 minutes ;

    member this.GetPort(): Async = this._GetPort(DateTime.Now)

    member this._GetPort(startTime: DateTime): Async = async {
        match this._TryGetOpenPort() with
        | Some(port) -> port
        | None -> do
            if (DateTime.Now - startTime).TotalMinutes >= 5 then
                raise (Exception "Impossible d'ouvrir un port")
            else
                do! Async.Sleep(100)
                let! result = this._GetPort(startTime)
                result}

    member this._TryGetOpenPort(): Option = 
        // etc.

Cependant, je rencontre quelques incohérences de type étranges dans _GetPort ; la fonction indique que je renvoie un type de Async au lieu de Async.

5voto

Phillip Carter Points 445

C'est un peu contre-intuitif, mais la manière de faire fonctionner votre code serait la suivante :

member private this.GetPort(startTime: DateTime) =
    async {
        match this.TryGetOpenPort() with
        | Some port ->
            return port
        | None ->
            if (DateTime.Now - startTime).TotalMinutes >= 5 then
                raise (Exception "Impossible d'ouvrir un port")

            do! Async.Sleep(100)
            let! result = this.GetPort(startTime)
            return result
    }

member private this.TryGetOpenPort() = failwith "yeet" // TODO

J'ai pris la liberté de nettoyer quelques éléments et de rendre la méthode privée, car il semble que c'est ce que vous essayez principalement d'obtenir ici avec une manière interne plus détaillée pour obtenir le port.

La raison pour laquelle votre code ne compilait pas était parce que vous étiez incohérent dans ce que vous retourniez de la computation :

  • Dans le cas de Some(port), vous avez oublié un mot-clé return - ce qui est nécessaire pour remonter la valeur dans un Async
  • Votre expression if où vous lancez une exception avait une branche else mais vous n'avez pas utilisé de return des deux côtés. Dans ce cas, étant donné que vous ne souhaitez clairement rien retourner et simplement lancer une exception, vous pouvez omettre le else et le transformer en un flux de programme impératif comme dans du code non-asynchrone.

L'autre chose à considérer à l'avenir est de savoir si jeter une exception est ce que vous voulez, ou si simplement retourner un Résultat ou une option est la meilleure solution. Les exceptions ne sont pas intrinsèquement mauvaises, mais souvent beaucoup de programmation F# consiste à éviter leur utilisation s'il y a une bonne manière d'attribuer une signification à un type qui encapsule votre valeur de retour.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X