如何将空单例添加到字典类型?

How to add an Empty singleton to Dictionary type?

module Extension =  
    type Dictionary<'T,'U> with
        member this.Update (x: Dictionary<_,_>) =
            for kvp in x do
                this.[kvp.Key] <- kvp.Value
            this
        /// This is wrong too, I wanted to use
        /// static let EmptyDictionary = Dictionary<'T,'U>() 
        static member EmptyDictionary = Dictionary<'T,'U>()
        /// Should not modify it, needs to be readonly.
        member this.Empty = Dictionary<'T,'U>.EmptyDictionary

为了模仿python字典update的功能,我需要一个空字典,以避免每次不需要更新时都实例化一个新字典。 (我也可以使用 null,但通常我会避免使用它。)

上面有警告说"a type constraint when 'T: equality is missing".

更新

以下演示了我的代码的用例。

假设 x 是一个字典,我可以通过 x.Update y

将它与 y 合并(更新 x

如果我不想更新x但仍然需要传入一个y,我可以使用x.Update x.Empty

我没有完全理解这个问题,但是写 new Dictionary<'K, 'V>() 似乎在 'K 上引入了 equality 约束。但是由于泛型类型本身不需要约束,这会导致不匹配。

所以,我不知道如何使用您使用的样式来修复定义,但无论如何我可能会使用一些不同的东西:

type Dictionary<'T,'U> with
    member this.Update (x: IDictionary<_,_>) =
        for kvp in x do
            this.[kvp.Key] <- kvp.Value
        this

module Dictionary =
  let Empty<'T, 'U when 'T : equality> = Dictionary<'T,'U>()

这利用了这样一个事实,即您可以拥有一个与类型同名的模块,因此它添加了 Update 作为扩展名,但 Dictionary.Empty 是一个通用值。这让你写:

Dictionary.Empty.Update(dict [1, "hi"; 2, "bye"])

根据 F# 规范:

14.11 CLI 方法的附加约束

F# treats some CLI methods and types specially, because they are common in F# > programming and cause extremely difficult-to-find bugs. For each use of the > following constructs, the F# compiler imposes additional ad-hoc constraints:

  • x.Equals(yobj) requires type ty : equality for the static type of x

  • x.GetHashCode() requires type ty : equality for the static type of x

  • new Dictionary() requires A : equality, for any overload that does not > take an IEqualityComparer

因此,如果您不打算改变空字典,那么您可以为 Dictionary<'K, 'V> 使用不同的构造函数重载并传递默认比较器。

此外,当前静态成员 EmptyDictionary 将在每次调用时 return 一个新的字典实例,我不确定这是不是故意的。您可以使用专用类型为每对类型参数存储空字典的唯一单例实例

open System.Collections.Generic

module Extension =
    type EmptyDictionaryHolder<'T, 'U>() = 
        static let value = new Dictionary<'T, 'U>(EqualityComparer<'T>.Default)
        static member Value: IDictionary<'T, 'U> = value :> _

    type IDictionary<'T,'U> with
        static member EmptyDictionary = EmptyDictionaryHolder<'T, 'U>.Value

        member this.Update (x: IDictionary<_,_>) =
            for kvp in x do
                this.[kvp.Key] <- kvp.Value
            this

        member this.Empty = Dictionary<'T,'U>.EmptyDictionary