5

重複の可能性:
タイプ拡張エラー

System.Collections.Generic.Dictionary に F# の拡張メソッドを追加したいと考えています。問題は、型制約を正しく取得できないように見えることです。私は次のようなものがうまくいくことを望んでいました:

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 に答える