2010-05-13 44 views
2

我已经创建了一个F#类来表示其分配一个元件对于特定枚举的每个值的数组。我使用的是创建一个从枚举值到数组索引字典的显式构造,以及项目属性,以便您可以编写表达式:在F#使用泛型创建EnumArray型

let my_array = new EnumArray<EnumType, int> 
my_array.[EnumType.enum_value] <- 5 

不过,我发现了以下晦涩编译错误的下面标有'// FS0670'的行。

error FS0670: This code is not sufficiently generic. 
The type variable ^e when ^e : enum<int> and ^e : equality 
and ^e : (static member op_Explicit : ^e -> int) 
could not be generalized because it would escape its scope. 

我很茫然 - 任何人都可以解释这个错误吗?

type EnumArray< 'e, 'v when 'e : enum<int> //' 
         and 'e : equality 
         and 'e : (static member op_Explicit : 'e -> int) > = 
    val enum_to_int : Dictionary<'e, int> //' 
    val a : 'v array //' 

    new() as this = 
     { 
      enum_to_int = new Dictionary<'e, int>() //' 
      a = Array.zeroCreate (Enum.GetValues(typeof<'e>).Length) //' 
     } 
     then 
      for (e : obj) in Enum.GetValues(typeof<'e>) do //' 
       this.enum_to_int.Add(e :?> 'e, int(e :?> 'e)) 

    member this.Item 
     with get (idx : 'e) : 'v = this.a.[this.enum_to_int.[idx]] // FS0670 
     and set (idx : 'e) (c : 'v) = this.a.[this.enum_to_int.[idx]] <- c 

回答

5

在这里你去:

open System 
open System.Collections.Generic 

type EnumArray<'e, 'v when 'e : enum<int> and 'e : equality>() = 
    let dict = new Dictionary<'e, int>() //' 
    let values = Enum.GetValues(typeof<'e>) //' 
    let a = Array.zeroCreate values.Length 
    do 
     for (o : obj) in values do 
      let e = o :?> 'e //' 
      dict.Add(e, LanguagePrimitives.EnumToValue(e)) 
    member this.Item 
     with get idx = a.[dict.[idx]] 
     and set idx c = a.[dict.[idx]] <- c 

let d = new EnumArray<StringSplitOptions, string>() 
d.[StringSplitOptions.None] <- "foo" 
d.[StringSplitOptions.RemoveEmptyEntries] <- "bar" 

一个关键方面是LanguagePrimitives.EnumToValue,这消除了对静态成员的约束的需要。 (使用静态成员约束是不够的,但是当事情失败时,编译器诊断更糟糕。)