首页 文章

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

提问于
浏览
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,我再次遇到编译错误 .

我不想在我的问题中过于具体,因为我认为这种方法存在缺陷吗?我该怎么办呢?

(Edited to add: ,发布@ Daniel的回答

唉,这似乎是我不能理解上下文以便理解答案的情况之一,所以...

我想我理解内联和不同的约束在你的答案中做了什么,但作为一个F#新手,你是否会介意对这些事情进行一些扩展,以便我可以检查一下我的理解是不是基于什么?谢谢 .

)

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上的Statically Resolved Type Parameters .

相关问题