我正在开发一个函数,该模式匹配f#中的一些用户定义类型并将它们转换为字符串。部分代码如下所示:
let gsToString (gs : general_structure) : string =
match gs with
| Date(Scattered(Eom(Ascending))) -> "Date(Scattered(Eom(Ascending)))"
| Date(Scattered(Eom(SameDate(dt)))) -> "Date(Scattered(Eom(SameDate(" + dt.ToString() + "))))"
| Number(AllNegative(Int1(Neither))) -> "Number(AllNegative(Int1(Neither)))"
| Number(AllNegative(Int1(SameInt(si)))) -> "Number(AllNegative(Int1(SameFloat(" + si.ToString() + "))))"
此功能中还有许多其他类型匹配,但这些应该足以传达问题。此外,导致问题的类型是:
| SameDate of System.DateTime
| SameFloat of float
显然,做第一个将general_structure类型转换为字符串的模式匹配函数是非常简单的。但是,我的下一个函数出现问题(需要稍后在代码中调用),我需要将字符串表示重新转换回general_structure。问题区域如下所示:
let stringToGS (str : string) : general_structure =
match str with
| "Date(Scattered(Eom(Ascending)))" -> Date(Scattered(Eom(Ascending)))
| "Date(Scattered(Eom(SameDate(dt))))"-> Date(Scattered(Eom(SameDate(System.DateTime.Parse dt))))
| "Number(AllNegative(Int1(Neither)))" -> Number(AllNegative(Int1(Neither)))
| "Number(AllPositive(Float1(SameFloat(sf))))" -> Number(AllPositive(Float1(SameFloat((float) sf))))
尽管stringToGS函数中的第一个和第三个案例工作得很好,但我无法找到将其他案例转换回原始格式的方法。如果有任何方法在模式匹配语句中取一个字符串(在这种情况下它将是dt和fs)并以某种方式解析模式的那部分以便返回不同的值(在这种情况下我试图制作它们分别是System.DateTimes和Floats)然后返回到它们的原始形式:
Date(Scattered(Eom(SameDate(dt))))
Number(AllPositive(Float1(SameFloat(sf))))
?我将不胜感激任何帮助。
编辑:
我能够通过对导致问题的案例的if语句执行以下操作来解决问题:
if str.Contains("Scattered(Eom(SameDate")
then
let p1 = str.IndexOf(")")
let p2 = str.LastIndexOf("(")
let dt1 = str.Remove(p1)
let dt2 = dt1.Substring(p2 + 1)
let date = System.DateTime.Parse dt2
Date(Scattered(Eom(SameDate(date))))
然后,我可以在所有不包含嵌套数据的类型上进行正常的模式匹配。
答案 0 :(得分:2)
如果课程数量有限并且您不想使用序列化库,您也可以使用活动模式:
open System
let (|RegexMatch|_|) pattern input =
let matches = System.Text.RegularExpressions.Regex.Matches(input, pattern)
if matches.Count = 1 then Some matches.[0].Groups.[1].Value
else None
type GeneralStructure =
| NoPayload
| DatePayload of DateTime
| StringPayload of string option
let toString = function
| NoPayload -> "NoPayload"
| DatePayload dt -> sprintf "DatePayload(%d)" <| dt.ToBinary()
| StringPayload None -> "StringPayload(None)"
| StringPayload (Some s) -> sprintf "StringPayload(Some(%s))" s
let fromString = function
| "NoPayload" -> NoPayload
| "StringPayload(None)" -> StringPayload None
| RegexMatch @"DatePayload\((.*)\)" dt -> DatePayload <| DateTime.FromBinary(Int64.Parse dt)
| RegexMatch @"StringPayload\(Some\((.*)\)\)" msg -> StringPayload <| Some msg
| o -> failwithf "Unknown %s %s" typeof<GeneralStructure>.Name o
let serialized = StringPayload <| Some "Foo" |> toString
let deserialized = fromString serialized
let serialized' = DatePayload DateTime.UtcNow |> toString
let deserialized' = fromString serialized'
// val serialized : string = "StringPayload(Some(Foo))"
// val deserialized : GeneralStructure = StringPayload (Some "Foo")
// val serialized' : string = "DatePayload(5247430828937321388)"
// val deserialized' : GeneralStructure = DatePayload 06.08.2015 18:04:10
请注意,正则表达式并非万无一失,我只是为了适应这些情况。