5

可能重复:
类型扩展错误

我想将 F# 中的扩展方法添加到 System.Collections.Generic.Dictionary。问题是我似乎无法正确设置类型约束。我希望像下面这样的东西会起作用:

type Dictionary<'k, 'd when 'k : equality> with

   static member ofList (xs:list<'k * 'd>) : Dictionary<'k, 'd> =
       let res = new Dictionary<'k, 'd> ()
       for (k, d) in xs do
           res.Add (k, d)
       res

但是,编译器抱怨我的声明与 Dictionary 的声明不同。当我忽略等式约束时,它不会产生那个特定的错误。但随后它警告说它丢失了。非常感谢任何提示,最好是“降低警告级别”的其他提示:-)

编辑

非常感谢 KVB 提供了我想要的答案。

type Dictionary<'k, 'd> with

static member ofList (xs:list<'k * 'd>) : Dictionary<'k, 'd> =

    let res = new Dictionary<'k, 'd> (EqualityComparer<'k>.Default)
    for (k, d) in xs do
        res.Add (k, d)
    res

编辑:这是一个更好地解释我对 RJ 的回复的例子。它表明在实例化类型时类型参数是可选的,只要编译器可以推断它们。它编译时没有警告或错误。

type System.Collections.Generic.Dictionary<'k, 'd> with
   static member test (dict:System.Collections.Generic.Dictionary<'k, 'd>) : bool =
        dict.Values |> List.ofSeq |> List.isEmpty


let test (x:System.Collections.Generic.Dictionary<'k, 'd>) =
    System.Collections.Generic.Dictionary.test x
4

3 回答 3

5

由于某种原因,类型参数的名称必须匹配 - 这对我来说很好

open System.Collections.Generic
type Dictionary<'TKey, 'TValue>  with
   static member ofList (xs:list<'k * 'd>) : Dictionary<'k, 'd> =
       let res = new Dictionary<'k, 'd> ()
       for (k, d) in xs do
           res.Add (k, d)
       res

我不知道为什么会这样(看规范的 30 秒也没有提供任何线索)。

更新- 错误实际上是当Dictionary参数与方法中写入的相同时 - 做

type Dictionary<'a, 'b>  with
   static member ofList (xs:list<'k * 'd>) : Dictionary<'k, 'd> =
       let res = new Dictionary<'k, 'd> ()
       for (k, d) in xs do
           res.Add (k, d)
       res

工作得很好。这实际上是有道理的。当参数相同时,'k:equality由于new Dictionary<'k,'d>. 但是,由于某种原因,我们不能在扩展定义中放置约束(避免重复?),所以会出现错误。

于 2012-12-05T11:16:48.907 回答
3

如果您需要ofSeq各种集合的函数,您可以考虑使用类似于 C# 集合初始化程序的方法。也就是说,使其适用于任何具有Add方法的集合。这也回避了您当前的问题。

open System.Collections.Generic
open System.Collections.Concurrent

module Dictionary =
  let inline ofSeq s = 
    let t = new ^T()
    for k, v in s do
      (^T : (member Add : ^K * ^V -> ^R) (t, k, v)) |> ignore
    t

module Collection =
  let inline ofSeq s = 
    let t = new ^T()
    for v in s do
      (^T : (member Add : ^V -> ^R) (t, v)) |> ignore
    t

open Dictionary

let xs = List.init 9 (fun i -> string i, i)
let d1 : Dictionary<_,_> = ofSeq xs
let d2 : SortedDictionary<_,_> = ofSeq xs
let d3 : SortedList<_,_> = ofSeq xs

open Collection

let ys = List.init 9 id
let c1 : ResizeArray<_> = ofSeq ys
let c2 : HashSet<_> = ofSeq ys
let c3 : ConcurrentBag<_> = ofSeq ys

有趣的是,您甚至可以将其限制为具有特定构造函数重载的集合类型。例如,如果你想使用结构相等,你可以这样做:

let t = (^T : (new : IEqualityComparer< ^K > -> ^T) (HashIdentity.Structural))
于 2012-12-05T20:28:55.793 回答
0

您将无法摆脱警告,因为您指的是不存在的类型, Dictionary而不是Dictionary<_,_>. 如果这是您想要访问它的方式,您可以制作一个 Dictionary 模块。

open System.Collections.Generic

type Dictionary<'a,'b>  with
  static member ofList (xs:list<'k*'v>) =
      let res = new Dictionary<_,_> ()
      for k, v in xs do
          res.Add (k, v)
      res    

module Dictionary = 
   let ofList xs = Dictionary<_,_>.ofList xs

然后你摆脱警告。

Dictionary.ofList ["1",1;"2",2];;
val it : Dictionary<string,int> = dict [("1", 1); ("2", 2)]
于 2012-12-05T13:34:00.777 回答