F # 9: Option de type

Si C # a le concept de null pour les types de référence et de Nullabe pour les structures. Cela peut prendre l'une des 2 formes suivantes (pour la démonstration, j'utilise ici le type int, mais le type peut être n'importe quelle structure).

  • Nullable
  • int?

Clause de non-responsabilité
   Nullabe  Nullable<T> ,    - ,    


Ils sont tous les deux équivalents.

La classe Nullable fournit plusieurs propriétés et méthodes d'assistance qui facilitent le travail avec les types et les structures null. Ce sont les suivants:

  • Hasvalue
  • Valeur
  • GetValueOrDefault ()
  • GetValueOrDefault (T)

Il y a quelque chose de légèrement différent de F # sous la forme d'un type Option , qui est un type plus convivial F # qui préfère ne pas traiter avec null, mais préfère traiter les choses en termes de "Peut contenir une valeur de type" ou "Peut ne pas avoir valeur. " Cela ressemble à Nullable, mais à la fin c'est du type F #, vous pouvez donc vous attendre à ce qu'il soit utilisé normalement dans les choses F #.

Une autre chose à noter avec le type Option F # est qu'il peut être utilisé pour tout type, pas seulement pour les structures. Ceci est différent de .NET Nullable, qui ne peut être utilisé qu'avec des structures.

La valeur None est utilisée lorsqu'il n'y a pas de valeur; sinon, l'expression Some (...) attribue une valeur. Les valeurs Some et None peuvent être utilisées lors de la correspondance avec un modèle, dont nous verrons un exemple dans cet article.

Comme Nullable, le type Option F # a plusieurs propriétés / méthodes d'assistance, qui sont présentées dans le tableau ci-dessous.

Aucun
'Option T
Une propriété statique qui vous permet de créer une valeur de paramètre avec une valeur None.
Isnone
bool
Renvoie true si le paramètre est None.
Issome
bool
Renvoie true si le paramètre a une valeur autre que None.
Certains
'Option T
Un membre statique qui crée un paramètre dont la valeur n'est pas None.
Valeur
«T
Renvoie une valeur de base ou lève une exception NullReferenceException si la valeur est None.

Création d'options


Donc, maintenant que nous savons quels sont les types d'options, comment les créer. Regardons quelques exemples. Notez que dans cet exemple, j'ai utilisé les méthodes d'assistance IsSome / IsNone. Personnellement, je crois que la comparaison avec un échantillon est la meilleure façon, car elle vous aidera à comparer tous les cas, y compris l'option Non.

En fait, je vais vous montrer à quel point il est facile de se tromper lorsque vous travaillez avec des types d'options si vous décidez d'utiliser des méthodes d'assistance, mais examinons d'abord un exemple du bon cas.

 let someInt = Some(43) let someString = Some("cat") let printTheOption (opt :Option<'a>) = printfn "Actual Option=%A" opt printfn "IsNone=%b, IsSome=%b Value=%A\r\n\r\n" opt.IsNone opt.IsSome opt.Value printfn "let someInt = Some(43)" printfn "let someString = Some(\"cat\")" printfn "printTheOption (someInt)" printTheOption someInt printfn "printTheOption (someString)" printTheOption someString 

image

Mais que se passe-t-il si nous essayons à nouveau en utilisant ce code, où nous avons None pour la valeur Option, que nous transmettrons à la fonction printTheOption:

 let demoNone = None let printTheOption (opt :Option<'a>) = printfn "Actual Option=%A" opt printfn "IsNone=%b, IsSome=%b Value=%A\r\n\r\n" opt.IsNone opt.IsSome opt.Value printfn "let demoNone = None" printfn "printTheOption demoNone" printTheOption demoNone 

image

Comme vous pouvez le voir, nous avons un problème ici. Le problème est que nous avons essayé d'obtenir la valeur Option en utilisant la propriété auxiliaire Option.Value, dans ce cas, c'est None, nous avons donc obtenu une exception NullReferenceException. Il est indiqué dans le tableau ci-dessus que lorsque vous utilisez des propriétés et des méthodes auxiliaires, vous pouvez obtenir une exception. Eh bien, vous pourriez utiliser la méthode IsNone et vous vérifieriez toujours la valeur en utilisant cela lorsque vous pourriez simplement utiliser une belle correspondance de modèle propre.

Si vous ne pouvez pas l'accepter, demandez-vous combien de fois vous avez dû vérifier la valeur nulle lors de l'utilisation de C #. Cela a même conduit les gens à inclure des constructions fonctionnelles, telles que Maybe Null Monad, dans du code .NET standard.

Donc, maintenant que nous avons vu le danger d'utiliser des méthodes / propriétés d'assistance, tournons maintenant notre attention vers la façon dont nous pourrions éviter ces exceptions:

 et printTheOption (opt :Option<'a>) = match opt with | Some a -> printfn "opt is Some, and has value %A" a | None -> printfn "opt is None" let demoNone = None let someInt = Some 1 let someString = Some "crazy dude in the monkey house" printTheOption demoNone printTheOption someInt printTheOption someString 

Mon opinion personnelle est qu'il est plus lisible que le code qui serait parsemé d'IsSome / IsNone partout. Ceci, bien sûr, est l'affaire de tous, mais le fait que nous ayons couvert toutes les bases ici dans cette fonction simple ne peut être ignoré.

image

Option vs Null


Nous avons donc parlé d'Option en F # par rapport à Nullabe, et nous savons que le type Option peut être utilisé avec n'importe quel type, tandis que Nullable ne peut être utilisé qu'avec des structures. Mais qu'en est-il des types d'options par rapport aux types de référence standard dans .NET. Eh bien, une grande victoire pour Option est que lorsque vous utilisez le type de référence dans .NET, vous avez affaire à une référence de pointeur, qui en tant que telle peut être définie sur null. Toutefois, le type de l'objet reste le même qu'il a été déclaré, qui peut contenir une référence valide à l'objet dans le tas (Heap) ou peut être null.

Il serait normal d'écrire comme ceci:

 string s1 = "cats"; int s1Length = s1.Length; string s2 = null; int s2Length = s2.Length; 

Cela sera compilé avec succès. Cependant, lorsque nous l'exécuterons, nous aurons une NullReferenceException, pour laquelle nous serons obligés de sortir pour protéger tout le code de la présence possible de null. Cela devient fastidieux assez rapidement, même si vous avez une jolie petite classe de protection qui vérifiera la valeur et la gérera / lèvera une exception plus significative.

Cette capture d'écran utilise LinqPad, donc cela peut sembler un peu inhabituel si vous n'avez jamais vu LinqPad auparavant, mais croyez-moi, vous obtenez toujours le même résultat dans un IDE différent.

image

Voyons maintenant à quoi ressemblera le code équivalent en F #

 let s1 = "Cats" let s1Length = s1.Length; let s2 = None let s2Length = s2.Length; //excplicily string typed None let s3 = Option.None let s3Length = s3.Length; 

Sur ce code, vous obtiendrez une erreur de compilation immédiate, car s3 sera considéré comme un autre type qui n'a pas la propriété «Length».

Comparaison des options


Les types d'options sont considérés comme égaux, ils sont du même type et les types qu'ils contiennent sont égaux, ce qui obéit aux règles d'égalité du type maintenu.

Donc, ce genre de chose peut conduire à une erreur de compilation immédiate en F #

 let o1 = Some 1 let o2 = Some "Cats" printfn "o1=o2 : %b" (o1 = o2) 

image

Cela fonctionnera comme prévu car les types sont les mêmes

 let o1 = Some "Cats" let o2 = Some "Cats" let o3 = Some "cats" printfn "o1=o2 : %b" (o1 = o2) printfn "o2=o3 : %b" (o2 = o3) 

image

Source: https://habr.com/ru/post/fr470918/


All Articles