我有一个F#判别联合类型,我希望对用于构造联合类型的任何值应用一些“构造函数逻辑”。假设联合类型看起来像这样:
type ValidValue =
| ValidInt of int
| ValidString of string
// other cases, etc.
现在,我想对实际传入的值应用一些逻辑,以确保它们是有效的。为了确保我不会处理那些不真正有效(没有使用验证逻辑构造)的ValidValue
实例,我将构造函数设为私有,并公开一个公共函数来强制执行我的逻辑以构造它们。
type ValidValue =
private
| ValidInt of int
| ValidString of string
module ValidValue =
let createInt value =
if value > 0 // Here's some validation logic
then Ok <| ValidInt value
else Error "Integer values must be positive"
let createString value =
if value |> String.length > 0 // More validation logic
then Ok <| ValidString value
else Error "String values must not be empty"
这个方法能够让我实施验证逻辑并确保每个ValidValue
实例都是有效的。但问题在于,模块外部没有人能够对ValidValue
进行模式匹配以检查其结果,从而限制了Discriminated Union的实用性。
我希望允许外部用户仍然像使用任何其他DU一样对ValidValue
进行模式匹配和操作,但如果它具有私有构造函数,则不可能实现。我能想到的唯一解决方案是在单个情况下将DU中的每个值包装在一个带有私有构造函数的联合类型中,并保留实际的ValidValue
构造函数。这将向外部公开情况,允许它们进行匹配,但仍然大部分防止外部调用者构造它们,因为实例化每种情况所需的值具有私有构造函数:
type VInt = private VInt of int
type VString = private VString of string
type ValidValue =
| ValidInt of VInt
| ValidString of VString
module ValidValue =
let createInt value =
if value > 0 // Here's some validation logic
then Ok <| ValidInt (VInt value)
else Error "Integer values must be positive"
let createString value =
if value |> String.length > 0 // More validation logic
then Ok <| ValidString (VString value)
else Error "String values must not be empty"
现在调用者可以匹配
ValidValue
的情况,但是他们无法读取联合类型中包含的实际整数和字符串值,因为它们被包装在具有私有构造函数的类型中。可以通过为每种类型创建value
函数来解决这个问题:module VInt =
let value (VInt i) = i
module VString =
let value (VString s) = s
不幸的是,现在呼叫者的负担增加了:
// Example Caller
let result = ValidValue.createInt 3
match result with
| Ok validValue ->
match validValue with
| ValidInt vi ->
let i = vi |> VInt.value // Caller always needs this extra line
printfn "Int: %d" i
| ValidString vs ->
let s = vs |> VString.value // Can't use the value directly
printfn "String: %s" s
| Error error ->
printfn "Invalid: %s" error
有没有更好的方法,在不增加后续负担的情况下,强制执行我想要的构造函数逻辑?
VInt
等添加Value
成员属性,这样您就可以只写vi.Value
而不是vi |> VInt.value
。 - TheQuickBrownFox