F# 如何将通用判别并集转换为obj
给一个像杜邦一样的F# 如何将通用判别并集转换为obj,f#,F#,给一个像杜邦一样的 type Result<'a, 'b> = Ok of 'a | Error of 'b 迄今为止的所有尝试都将'a和'b的类型限制为obj let toObjResult (x:obj) = match x with | :? Result<'a, 'b> as r -> match r with | Ok a -> Ok (box a) | Error b -> Error (box
type Result<'a, 'b> = Ok of 'a | Error of 'b
迄今为止的所有尝试都将'a
和'b
的类型限制为obj
let toObjResult (x:obj) =
match x with
| :? Result<'a, 'b> as r ->
match r with
| Ok a -> Ok (box a)
| Error b -> Error (box b)
| _ -> Error <| (exn "Invalid type" |> box)
您必须在匹配表达式中匹配结果类型的确切泛型类型参数
let matchR r =
match r with
| Ok a -> Ok (box a)
| Error b -> Error (box b)
let toObjResult (x:obj) =
match x with
| :? Result<bool, _> as r -> matchR r
| :? Result<string, int> as r -> matchR r
| :? Result<_, Exception> as r -> matchR r
| _ -> Error (box "Invalid type" )
let matchR=
匹配
|确定a->确定(框a)
|错误b->错误(框b)
让我们看看结果(x:obj)=
将x与
| :? 结果为r->matchR r
| :? 结果为r->matchR r
| :? 结果为r->matchR r
|->错误(框“无效类型”)
遗憾的是,您无法在未实现的类型参数上进行匹配(这非常糟糕)如果不使用反射、枚举所有类型或修改类型,就无法进行匹配 使用反射可能很慢,但可以让你做你想做的事情(参见[the
GenericType
active pattern]),来自@robkuz的答案通过列出你想涵盖的所有案例来说明如何做到这一点——问题是,这不能很好地扩展
最后,如果您愿意修改结果
类型,您可以添加一个非通用接口,让您将值作为装箱值获取:
type IBoxedResult =
abstract Boxed : Result<obj, obj>
and Result<'a, 'b> =
| Ok of 'a
| Error of 'b
interface IBoxedResult with
member x.Boxed =
match x with
| Ok v -> Ok (box v)
| Error v -> Error (box v)
对有关匹配泛型的问题的回答可能会有所帮助。这样做似乎不可取,因为它会将编译器错误替换为运行时错误。为什么要这样做?不会有运行时错误,因为类型保证为
Result
。许多函数通过http调用,每个函数都将返回Result
。如果是Ok
,则返回200和值。如果是Error
,则返回400和错误消息。问题是如何获得相应的'a
和'b
值。模式匹配将不起作用,因为类型未知,因此将其转换为obj
的方法解决了该问题。有趣的是我不能只匹配未实现的类型参数。我唯一能保证的是b'
是一个例外。对于a'
,它可以是任何值,因此不可能对所有值进行模式匹配。结果用IBoxedResult
扩展。更简单的解决方案。
let toObjResult (x:obj) =
match x with
| :? Result<'a, 'b> as r ->
match r with
| Ok a -> Ok (box a)
| Error b -> Error (box b)
| _ -> Error <| (exn "Invalid type" |> box)
System.InvalidCastException: Unable to cast object of type 'Ok[System.Boolean,System.Object]' to type 'Result`2[System.Object,System.Object]'.
let matchR r =
match r with
| Ok a -> Ok (box a)
| Error b -> Error (box b)
let toObjResult (x:obj) =
match x with
| :? Result<bool, _> as r -> matchR r
| :? Result<string, int> as r -> matchR r
| :? Result<_, Exception> as r -> matchR r
| _ -> Error (box "Invalid type" )
type IBoxedResult =
abstract Boxed : Result<obj, obj>
and Result<'a, 'b> =
| Ok of 'a
| Error of 'b
interface IBoxedResult with
member x.Boxed =
match x with
| Ok v -> Ok (box v)
| Error v -> Error (box v)
[ box (Ok true)
box (Ok 1) ]
|> List.map (fun o -> (o :?> IBoxedResult).Boxed)