如何将字符串解析为任何 F# 数据?

How to parse string to any F# data?

在 F# 中,任何 data 都可以通过函数 sprintf stringify,如下所示:

type someKindOfDataType = ...
let data : someKindOfDataType = ...
sprintf "%A" data

我们能否有一个反转函数来将字符串解析回 someKindOfDataType,如下所示:?

let parse<'someKingOfDataType> (s:string) : someKindOfDataType = ....

就像 javascript 中的 JSON.parse?

您描述的是通常所说的 序列化 - 从内存中的数据结构转换为可以通过网络传输的表示形式,这可能是 XML、JSON、二进制等 - 和 反序列化 - 相反。

sprintf "%A" 旨在提供方便的数据可视化表示,通常仅用于开发而非生产目的。它实际上并不进行序列化,因为没有办法反序列化。

如果您想将 F# 数据序列化为字符串,我建议通过 Newtonsoft.Json.

等库使用 JSON

请注意,这不会像 sprintf "%A" 那样生成看起来类似于 F# 源代码的字符串,因为目的不同。一个例子:

Newtonsoft.Json.JsonConvert.SerializeObject [|Some 3; None|]
// """[{"Case":"Some","Fields":[3]},null]"""

Newtonsoft.Json.JsonConvert.DeserializeObject<int option []> """[{"Case":"Some","Fields":[3]},null]"""
// [|Some 3; None|]

您需要提供要反序列化的类型,如果字符串不代表该类型的有效实例,此操作可能会引发异常。

标准的 .NET 方法通常是在您尝试解析的类型的 class 中使用 ParseTryParse 方法。

但在 F# 中,TryParse 函数不是很友好,因为它使用输出参数,F# 编译器仍然允许您将其视为元组,这使事情变得更好,但您仍然会期望要获得一个选项,这里有一个例子:

let a = Int32.Parse "5"
let b = 
    match Int32.TryParse "5" with
    | true, value -> Some value
    | _           -> None

如果你想使用一个库 F#+ 有两个函数 parsetryParse 可以为你完成以上所有事情:

#r @"FSharpPlus.dll"
open FSharpPlus
open System

let (a:int) = parse "5"
let (b:int option) = tryParse "5"
let (c: Net.IPAddress option) = tryParse "10.0.0.1"

// val a : int = 5
// val b : int option = Some 5
// val c : Net.IPAddress option = Some 10.0.0.1

只要类型定义了 ParseTryParse,它就可以工作。