我知道有更好的方法来解析F#中的JSON(比如FSharp.Data中的类型提供程序),但为了简单起见(因为我在fsx文件中执行此操作而且我没有'我还想处理Nuget + Paket用具),我在这里使用System.Web.Script.Serialization.JavaScriptSerializer
。
问题是当我尝试在字典中找到一个元素时,使用这个函数:
let isTestNet(): bool =
let json = SomeFuncThatGivesMeAString()
let jss = new JavaScriptSerializer()
let dict = jss.DeserializeObject(json) :?> Dictionary<string, obj>
for entry in dict do
if (entry.Key.Equals("testnet")) then
let result = entry.Value :?> bool
result
failwith "JSON response didn't include a 'testnet' element? " + json
编译器突出显示倒数第二行,但出现此错误:
error FS0001: This expression was expected to have type
unit
but here has type
bool
这笔交易是什么?我甚至在函数头中指定了类型。为什么期望一个单位?
答案 0 :(得分:3)
for
表达式应评估为unit
类型;将for
结尾的非 - unit
表达式不会以某种方式使其成为封闭函数的返回值。最终你需要放弃for
。
一种选择是改为使用Seq.tryFind
:
let isTestNet () : bool =
let dict =
let json = (* ... *)
let jss = JavaScriptSerializer()
jss.DeserializeObject json :?> Dictionary<string, obj>
match dict |> Seq.tryFind (fun entry -> entry.Key.Equals "testnet") with
| Some entry -> entry.Value :?> bool
| _ -> failwith ("JSON response didn't include a 'testnet' element? " + json)
(N.b。由于运算符优先级,错误消息的字符串连接必须括在括号中。)
虽然这很好,但Seq.tryFind
会进行 O(N)搜索,而Dictionary
本身会执行 O(1)搜索当直接使用时,如果字典是任何实际大小,这种方法是不可行的。
效率更高,稍微不那么明显(除了@ AntonSchwaighofer建议的改进):
let isTestNet () : bool =
let dict =
let json = (* ... *)
let jss = JavaScriptSerializer()
jss.DeserializeObject json :?> Dictionary<string, obj>
match dict.TryGetValue "testnet" with
| true, (:? bool as value) -> value
| true, _ -> failwithf "'testnet' element was not a bool? %s" json
| _ -> failwithf "JSON response didn't include a 'testnet' element? %s" json