7

所以,给定下面的代码

type MyClass () =
  let items = Dictionary<string,int>()
  do 
    items.Add ("one",1)
    items.Add ("two",2)
    items.Add ("three",3)
  member this.TryGetValue (key,value) =
    items.TrygetValue (key,value)
let c = MyClass () 

let d = Dictionary<string,int> ()
d.Add ("one",1)
d.Add ("two",2)
d.Add ("three",3)

以及下面的测试代码

let r1,v1 = d.TryGetValue "one"
let r2,v2 = c.TryGetValue "one"

r1,v1 行工作正常。r2,v2 线炸弹;抱怨 c.TryGetValue 必须被赋予一个元组。有趣的是,在每一行中,TryGetValue 的签名都是不同的。如何让我的自定义实现表现出与 BCL 版本相同的行为?或者,换一种方式问,既然F#(隐含)有元组参数、柯里化参数和BCL参数的概念,而且我知道如何区分柯里化和元组样式,我该如何强制第三种样式(a la BCL方法)?

如果不清楚,请告诉我。

4

2 回答 2

8

TryGetValue有一个 out 参数,因此您需要在 F# 中执行相同的操作(通过byref标记为OutAttribute):

open System.Runtime.InteropServices 
type MyDict<'K,'V when 'K : equality>() =  // '
    let d = new System.Collections.Generic.Dictionary<'K,'V>()
    member this.TryGetValue(k : 'K, [<Out>] v: byref<'V>) =
        let ok, r = d.TryGetValue(k)
        if ok then
            v <- r
        ok            

let d = new MyDict<string,int>()
let ok, i = d.TryGetValue("hi")
let mutable j = 0
let ok2 = d.TryGetValue("hi", &j)

F# 自动允许您将后缀输出参数转换为返回值,因此您只需编写一个以输出参数结尾的方法。

于 2010-04-27T22:10:31.017 回答
4

就个人而言,我从不喜欢bool TryXXX(stringToParseOrKeyToLookup, out parsedInputOrLookupValue_DefaultIfParseFailsOrLookupNotFound)整个 BCL 中使用的模式。虽然返回元组的 F# 技巧很好,但如果解析或查找失败,我实际上很少需要默认值。实际上,Some/None模式将是完美的(如Seq.tryFind):

type MyClass () =
  let items = System.Collections.Generic.Dictionary<string,int>()
  do 
    items.Add ("one",1)
    items.Add ("two",2)
    items.Add ("three",3)
  member this.TryGetValue (key) =
    match items.TryGetValue(key) with
        | (true, v) -> Some(v)
        | _ -> None

let c = MyClass()

let printKeyValue key =
    match c.TryGetValue(key) with
    | Some(value) -> printfn "key=%s, value=%i" key value
    | None -> printfn "key=%s, value=None" key

//> printKeyValue "three";;
//key=three, value=3
//val it : unit = ()
//> printKeyValue "four";;
//key=four, value=None
//val it : unit = ()
于 2010-12-06T20:40:09.563 回答