Dictionary 为字典键入扩展名错误<';K、 &x27;V>;

Dictionary 为字典键入扩展名错误<';K、 &x27;V>;,dictionary,f#,extension-methods,Dictionary,F#,Extension Methods,下面的类型扩展 module Dict = open System.Collections.Generic type Dictionary<'K, 'V> with member this.Difference(that:Dictionary<'K, 'T>) = let dict = Dictionary() for KeyValue(k, v) in this do if not (that.Contains

下面的类型扩展

module Dict =

  open System.Collections.Generic

  type Dictionary<'K, 'V> with
    member this.Difference(that:Dictionary<'K, 'T>) =
      let dict = Dictionary()
      for KeyValue(k, v) in this do
        if not (that.ContainsKey(k)) then
          dict.Add(k, v)
      dict
模块Dict=
open System.Collections.Generic
使用
成员:此差异(即:字典)=
让dict=Dictionary()
对于此do中的键值(k,v)
如果不是,那么
dict.Add(k,v)
字典
给出了错误:

签名和实现不兼容,因为类型参数“TKey”的声明需要格式为“TKey:equality”的约束

但当我添加约束时,它会产生错误:

此类型扩展的声明类型参数与原始类型“Dictionary”上声明的类型参数不匹配

这一点尤其神秘,因为下面的类型扩展没有约束,可以正常工作

type Dictionary<'K, 'V> with
  member this.TryGet(key) =
    match this.TryGetValue(key) with
    | true, v -> Some v
    | _ -> None
使用
成员:此。TryGet(键)=
将此.TryGetValue(键)与
|对,v->一些v
|无

现在我有了一个奇怪的想法:只有在访问某些成员时才需要约束吗?

问题在于您使用了
Add
方法。如果使用
Dictionary
的这种方法,则F#将强制
TKey
具有相等约束

在玩了一会儿之后,我甚至不确定是否有可能编写这个扩展方法。F#type系统似乎强制扩展方法的声明类型没有原始类型以外的其他约束(每当我添加
相等
约束时,我都会得到一个错误)。此外,Individual扩展方法中列出的类型不能与列出的类型不同。我已经尝试了许多方法,但无法使其正常工作

最接近的方法是非扩展方法,如下所示

let Difference (this : Dictionary<'K, 'T>) (that:Dictionary<'K, 'T> when 'K : equality) =
    let dict = Dictionary()
    for KeyValue(k, v) in this do
        if not (that.ContainsKey(k)) then
            dict.Add(k, v)
    dict
let Difference(this:Dictionary)(当'K:equality时,this:Dictionary)=
让dict=Dictionary()
对于此do中的键值(k,v)
如果不是,那么
dict.Add(k,v)
字典

也许另一个F#ninja能够证明我错了

,就我所知,以下代码起到了作用:

module Dict =
open System.Collections.Generic

type Dictionary<'K, 'V> with
    member this.Difference(that: Dictionary<'K,'V2>) = 
        let diff =
            this
            |> Seq.filter (fun x -> not <| that.ContainsKey(x.Key))
            |> Seq.map (fun x -> x.Key, x.Value)
        System.Linq.Enumerable.ToDictionary(diff, fst, snd)
模块Dict=
open System.Collections.Generic
使用
请记住此区别(即:字典)=
让差异=
这
|>Seq.filter(fun x->not Seq.map(fun x->x.Key,x.Value)
System.Linq.Enumerable.ToDictionary(差异、fst、snd)
(编辑:CKoenig有一个很好的答案。)

嗯,我也没有马上想到一个办法

这里有一个非类型安全的解决方案,可能会为其他人提供一些疯狂的灵感

open System.Collections.Generic  

module Dict =  
  type Dictionary<'K, 'V> with    
    member this.Difference<'K2, 'T when 'K2 : equality>(that:Dictionary<'K2, 'T>) =      
        let dict = Dictionary<'K2,'V>()      
        for KeyValue(k, v) in this do        
            if not (that.ContainsKey(k |> box |> unbox)) then          
                dict.Add(k |> box |> unbox, v)      
        dict

open Dict

let d1 = Dictionary()
d1.Add(1, "foo")
d1.Add(2, "bar")

let d2 = Dictionary()
d2.Add(1, "cheese")

let show (d:Dictionary<_,_>) =
    for (KeyValue(k,v)) in d do
        printfn "%A: %A" k v

d1.Difference(d2) |> show

let d3 = Dictionary()
d3.Add(1, 42)

d1.Difference(d3) |> show

let d4 = Dictionary()
d4.Add("uh-oh", 42)

d1.Difference(d4) |> show  // blows up at runtime
open System.Collections.Generic
模块Dict=
使用
成员。差异
模块Dict=
open System.Collections.Generic
使用
成员:此差异(即:字典)=
让dict=字典(this.Comparer)
对于此do中的键值(k,v)
如果不是,那么
dict.Add(k,v)
字典
编辑

依照

F#特别处理一些特定的CLI方法和类型,因为它们在F#编程中很常见,并且导致很难找到错误。对于以下构造的每次使用,F#编译器都会施加额外的特殊约束:

  • x.Equals(yobj)
    需要类型
    ty:equality
    用于静态类型的
    x
  • x.GetHashCode()
    需要类型
    ty:equality
    用于
    x
  • new Dictionary()
    要求
    A:equality
    ,对于不需要
    IEqualityComparer

哎呀……我奇怪的想法得到了证实。我已经尝试过几种方法,但我也觉得不可能。约束来自何方?它是否与贾里德指出的
Add
的使用有关?除了编译器告诉你之外,还有其他方法知道何时需要这些约束吗?参见14.11:显然
new Dictionary
添加了约束,这解释了为什么
到Dictionary
是可以的。我永远不会达到这个目的。为什么用比较器初始化字典会绕过相等约束?@Daniel,我怀疑深夜阅读规范可能会产生与熬夜相反的效果——无论如何,对我来说;)
module Dict =

  open System.Collections.Generic

  type Dictionary<'K, 'V> with
    member this.Difference(that:Dictionary<'K, 'T>) =
        let dict = Dictionary(this.Comparer)
        for KeyValue(k, v) in this do
            if not (that.ContainsKey(k)) then
                dict.Add(k, v)
        dict