如何正确模式匹配 JsonConversions
How to properly pattern match JsonConversions
您好,我有以下代码,它按预期工作,但是当我在 Option.defaultWith
函数中进行模式匹配时,编译器警告我模式匹配不完整。有没有更聪明的方法来实现相同的效果但没有警告?
我一直在考虑为其余情况抛出异常,但这很丑陋。
namespace JsonParser
open System
open System.Globalization
open FSharp.Data
open FSharp.Data.Runtime
type public Key = string
type public Value =
| Int of int
| Double of double
| Decimal of decimal
| String of string
| DateTime of DateTime
| Boolean of Boolean
| Array of Value []
| Guid of Guid
| Null
| Object of Record []
and public Record =
{ Key: Key
Value: Value }
module public Json =
let private culture = CultureInfo.InvariantCulture
let private emptyArray = Array.empty<String>
let rec private map (value: JsonValue) =
JsonConversions.AsInteger culture value
|> Option.map Value.Int
|> Option.orElseWith (fun () -> JsonConversions.AsDecimal culture value |> Option.map Value.Decimal)
|> Option.orElseWith (fun () -> JsonConversions.AsFloat emptyArray true culture value |> Option.map Decimal |> Option.map Value.Decimal)
|> Option.orElseWith (fun () -> JsonConversions.AsGuid value |> Option.map Value.Guid)
|> Option.orElseWith (fun () -> JsonConversions.AsDateTime culture value |> Option.map Value.DateTime)
|> Option.orElseWith (fun () -> JsonConversions.AsBoolean value |> Option.map Value.Boolean)
|> Option.defaultWith (fun () ->
match value with
| JsonValue.String x -> Value.String x
| JsonValue.Null -> Value.Null
| JsonValue.Array x ->
x
|> Array.map map
|> Value.Array
| JsonValue.Record x ->
x
|> Array.map (fun (x, y) ->
{ Key = x
Value = map y })
|> Value.Object)
答案实际上取决于您希望如何处理 JSON 数据中的各种极端情况。
JsonConversions
中的操作的实现方式是,只要可以合理地完成,它们就会尝试将值转换为目标类型。这意味着使用这些,值 true
、1
和 "yes"
将全部转换为布尔值 true
。这是你想要的吗?如果是这样,那么我可能只是在抛出异常的模式匹配中添加一个案例,说这种情况不应该发生:
match value with
| JsonValue.String x -> Value.String x
| JsonValue.Null -> Value.Null
| JsonValue.Array x -> (...)
| JsonValue.Record x -> (...)
| JsonValue.Float _ | JsonValue.Number _ | JsonValue.Boolean _ ->
failwith "should never happen: Numbers and booleans handled earlier!"
如果你想把JSON的值"yes"
变成Value.String("yes")
而不是Value.Boolean(true)
,那么直接在[=上进行模式匹配就容易多了20=]:
let rec private map (value: JsonValue) =
match value with
| JsonValue.Float f -> Value.Double f
| JsonValue.Number n -> Value.Decimal n
| JsonValue.Boolean b -> Value.Boolean b
| JsonValue.String x -> Value.String x
| JsonValue.Null -> Value.Null
| JsonValue.Array x ->
x |> Array.map map |> Value.Array
| JsonValue.Record x ->
x |> Array.map (fun (x, y) -> { Key = x; Value = map y }) |> Value.Object
您可以通过查看源代码中的相关文件找到有关 JsonConversions
工作原理的详细信息:JsonConversions and TextConversions.
您好,我有以下代码,它按预期工作,但是当我在 Option.defaultWith
函数中进行模式匹配时,编译器警告我模式匹配不完整。有没有更聪明的方法来实现相同的效果但没有警告?
我一直在考虑为其余情况抛出异常,但这很丑陋。
namespace JsonParser
open System
open System.Globalization
open FSharp.Data
open FSharp.Data.Runtime
type public Key = string
type public Value =
| Int of int
| Double of double
| Decimal of decimal
| String of string
| DateTime of DateTime
| Boolean of Boolean
| Array of Value []
| Guid of Guid
| Null
| Object of Record []
and public Record =
{ Key: Key
Value: Value }
module public Json =
let private culture = CultureInfo.InvariantCulture
let private emptyArray = Array.empty<String>
let rec private map (value: JsonValue) =
JsonConversions.AsInteger culture value
|> Option.map Value.Int
|> Option.orElseWith (fun () -> JsonConversions.AsDecimal culture value |> Option.map Value.Decimal)
|> Option.orElseWith (fun () -> JsonConversions.AsFloat emptyArray true culture value |> Option.map Decimal |> Option.map Value.Decimal)
|> Option.orElseWith (fun () -> JsonConversions.AsGuid value |> Option.map Value.Guid)
|> Option.orElseWith (fun () -> JsonConversions.AsDateTime culture value |> Option.map Value.DateTime)
|> Option.orElseWith (fun () -> JsonConversions.AsBoolean value |> Option.map Value.Boolean)
|> Option.defaultWith (fun () ->
match value with
| JsonValue.String x -> Value.String x
| JsonValue.Null -> Value.Null
| JsonValue.Array x ->
x
|> Array.map map
|> Value.Array
| JsonValue.Record x ->
x
|> Array.map (fun (x, y) ->
{ Key = x
Value = map y })
|> Value.Object)
答案实际上取决于您希望如何处理 JSON 数据中的各种极端情况。
JsonConversions
中的操作的实现方式是,只要可以合理地完成,它们就会尝试将值转换为目标类型。这意味着使用这些,值 true
、1
和 "yes"
将全部转换为布尔值 true
。这是你想要的吗?如果是这样,那么我可能只是在抛出异常的模式匹配中添加一个案例,说这种情况不应该发生:
match value with
| JsonValue.String x -> Value.String x
| JsonValue.Null -> Value.Null
| JsonValue.Array x -> (...)
| JsonValue.Record x -> (...)
| JsonValue.Float _ | JsonValue.Number _ | JsonValue.Boolean _ ->
failwith "should never happen: Numbers and booleans handled earlier!"
如果你想把JSON的值"yes"
变成Value.String("yes")
而不是Value.Boolean(true)
,那么直接在[=上进行模式匹配就容易多了20=]:
let rec private map (value: JsonValue) =
match value with
| JsonValue.Float f -> Value.Double f
| JsonValue.Number n -> Value.Decimal n
| JsonValue.Boolean b -> Value.Boolean b
| JsonValue.String x -> Value.String x
| JsonValue.Null -> Value.Null
| JsonValue.Array x ->
x |> Array.map map |> Value.Array
| JsonValue.Record x ->
x |> Array.map (fun (x, y) -> { Key = x; Value = map y }) |> Value.Object
您可以通过查看源代码中的相关文件找到有关 JsonConversions
工作原理的详细信息:JsonConversions and TextConversions.