4

私はF#を始めたばかりですが、キャストに関する問題のいくつかは私を非常に混乱させています。残念ながら、なぜ私をさらに混乱させているのかを理解しようとする私の背景を読んでいるので、私は一般的な説明に合うことができるいくつかの具体的な答えを探しています...

この関数によって生成された列挙型のReadOnlyCollection<'T>があります。

let GetValues<'T when 'T :> Enum> () =
    (new ReadOnlyCollection<'T>(Enum.GetValues (typeof<'T>) :?> 'T[])) :> IList<'T>

私がそれでやりたいのは、その値によって使用される列挙型のすべてのビット(つまり、ビット単位-またはリスト内のすべての値を一緒に)を見つけて、それを一般的な列挙型タイプ'Tとして返すことです。それを行うための明白な方法は、私にはこれであるように思われました:

let UsedBits<'T when 'T :> Enum> () =
    GetValues<'T>()
    |> Seq.fold (fun acc a -> acc ||| a) 0

...それがコンパイルに失敗することを除いて、「宣言された型パラメータ'T'は、コンパイル時に型パラメータを解決できないため、ここでは使用できません。」というエラーが発生します。

最初にInt32に変換することで、実際の作業を実行できます(この関数は、基になる型に関係なくすべての列挙型で機能するため、実際には実行したくありません)。

let UsedBits<'T when 'T :> Enum> () =
    GetValues<'T>()
    |> Seq.map (fun a -> Convert.ToInt32(a))
    |> Seq.fold (fun acc a -> acc ||| a) 0

...しかし、結果はInt32として生成されます。'Tにキャストし直そうとすると、再びコンパイルエラーが発生します。

どの詳細について質問すべきかわからないので、質問を具体的にしすぎたくないので、このアプローチの欠陥はどこにありますか?どうすればいいですか?

(追加するために編集:、@Danielの回答を投稿

残念ながら、これは私が答えを理解するのに十分な文脈を理解していない状況の1つであるように思われるので...

私はあなたの答えでインラインと異なる制約が何をしているのか理解していると思いますが、F#初心者なので、私の理解がベースから大きく外れていないことを確認できるように、それらのことを少し拡張していただけませんか?ありがとう。

)。

4

1 に答える 1

8

あなたはこれを行うことができます:

let GetValues<'T, 'U when 'T : enum<'U>>() = 
  Enum.GetValues(typeof<'T>) :?> 'T[]

let inline GetUsedBits() =
  GetValues() |> Seq.reduce (|||)

inlineより柔軟な制約、つまり'T (requires member ( ||| ))。これがない場合、コンパイラはILで表現できる制約を選択する必要があります。それができない場合は、具象型を選択する必要があります。この場合int、をサポートしているので選択します(|||)

より簡単な再現は次のとおりです。

let Or a b = a ||| b //add 'inline' to compare

詳細については、MSDNの静的に解決されたタイプパラメータを参照してください。

于 2013-01-22T21:05:22.613 に答える