如何通过专用功能强制创建Discriminated Union值?
意图:
我想依靠Creational Patterns来生成只有有效数据的结构.
因此,我认为我需要通过将其设为只读来限制DU值的使用.但是,对我来说,如何实现这一目标并不明显.
module File1 =
type EmailAddress =
| Valid of string
| Invalid of string
let createEmailAddress (address:System.String) =
if address.Length > 0
then Valid address
else Invalid address
module File2 =
open File1
let validEmail = Valid "" // Shouldn't be allowed
let isValid = createEmailAddress ""
let result = match isValid with
| Valid x -> true
| _ -> false
Run Code Online (Sandbox Code Playgroud)
我尝试了以下方法:
type EmailAddress =
private
| Valid of string
| Invalid of string
Run Code Online (Sandbox Code Playgroud)
但是,将DU类型设置为私有会破坏对创建函数的结果执行模式匹配的能力.
The*_*ght 11
这就是我们想到的东西.
您可以使用活动模式来确定要作为API向外部世界公开的案例,然后将DU的内部表示完全保密.
这会强制您使用公开公开的API来创建区分联合,但仍允许对结果进行模式匹配 - 如下所示:
module File1 =
type EmailAddress =
private
| Valid of string
| Invalid of string
let createEmailAddress (address:System.String) =
if address.Length > 0
then Valid address
else Invalid address
// Exposed patterns go here
let (|Valid|Invalid|) (input : EmailAddress) : Choice<string, string> =
match input with
| Valid str -> Valid str
| Invalid str -> Invalid str
module File2 =
open File1
let validEmail = Valid "" // Compiler error
let isValid = createEmailAddress "" // works
let result = // also works
match isValid with
| Valid x -> true
| _ -> false
Run Code Online (Sandbox Code Playgroud)
请注意,如果使用相同的模式名称,则可能必须添加上面显示的相当讨厌的类型注释 - 如果File2模块不存在,则需要这些注释以防止编译器错误- 如果您在API中公开API,这可能是相关的图书馆但没有使用它.如果您使用不同的模式名称,那显然不是问题.