[英]Casting to and from a type parameter in F#
我剛剛開始使用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的回答
唉,這似乎是我不能理解上下文以便理解答案的情況之一,所以...
我想我理解內聯和不同的約束在你的答案中做了什么,但作為一個F#新手,你是否會介意對這些事情進行一些擴展,以便我可以檢查一下我的理解是不是基於什么? 謝謝。
)
你可以這樣做:
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上的靜態已解析的類型參數 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.