在F#中输入和输出类型参数

时间:2013-01-22 20:29:22

标签: casting f# inline

我刚刚开始使用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#新手,你是否会介意对这些事情进行一些扩展,以便我可以检查我的理解是不是离开基地的路?感谢。

1 个答案:

答案 0 :(得分: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上的Statically Resolved Type Parameters

相关问题