使用bigint查找扩展F#数组

时间:2018-10-17 12:54:52

标签: f#

我想扩展F#数组,这样我就可以使用数组而不必转换为有限的let x: (typeof myExample)[]。相反,我想直接使用 enum myExample { value1, value2 } function getArrayWithNumberBaseEnumItems<T>(numberEnum: T): T[]{ let arrayWithEnumItems: T[] = []; for (let item in numberEnum) { if (isNaN(Number(item))) { arrayWithEnumItems.push(numberEnum[item] as any); console.log(numberEnum[item]); } } return arrayWithEnumItems; } let x = getArrayWithNumberBaseEnumItems(myExample); console.dir(x); // [0,1]

我能够向数组类型添加第二个长度方法,如下所示:

int

但是无法使用bigint语法调用type 'T ``[]`` with member this.LengthI: bigint = bigint this.Length member this.Item(index: bigint): 'T = this.[int index] 方法。

任何想法如何实现?我有可能吗?

1 个答案:

答案 0 :(得分:2)

我强烈怀疑,对于本机数组来说,这是不可能的。您可以验证自己是否可以重载索引访问权限,以适合其他集合。

如果您编译以下代码:

let myArray = [| "a" |]
let myList = [ "a" ]

let arrayElement = myArray.[11111]
let listElement = myList.[22222]

并检查生成的IL,您将看到在访问列表元素时编译为常规虚拟调用,同时有特殊CIL指令用于访问本机数组元素{{1} }。

ldelem

我猜想,特殊情况下数组访问单个指令的编译器逻辑也会绕过涉及扩展方法等的任何重载解析。

一种避免这种情况的方法是将数组包装为自定义类型,重载索引器将按您期望的方式工作。在大多数情况下,将包装器类型设为结构应可减少性能损失:

//000004: let arrayElement = myArray.[11111]
    IL_002c:  call       string[] Fuduoqv1565::get_myArray()
    IL_0031:  ldc.i4     0x2b67
    IL_0036:  ldelem     [mscorlib]System.String
    IL_003b:  stsfld     string '<StartupCode$51dff40d-e00b-40e4-b9cc-15309089d437>'.$Fuduoqv1565::arrayElement@4
    .line 5,5 : 1,33 ''
//000005: let listElement = myList.[22222]
    IL_0040:  call       class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string> Fuduoqv1565::get_myList()
    IL_0045:  ldc.i4     0x56ce
    IL_004a:  callvirt   instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_Item(int32)
    IL_004f:  stsfld     string '<StartupCode$51dff40d-e00b-40e4-b9cc-15309089d437>'.$Fuduoqv1565::listElement@5
    IL_0054:  ret

另一种方法是将该数组转换为基type [<Struct>] BigArray<'T>(array : 'T[]) = member this.LengthI: bigint = bigint array.Length member this.Item with get(index : int) = array.[index] and set (index : int) value = array.[index] <- value member this.Item with get(index : bigint) = array.[int index] and set (index : bigint) value = array.[int index] <- value let bigArray = BigArray myArray let bigArrayElement = bigArray.[0] let bigArrayElement2 = bigArray.[bigint 0] 类,然后可以在该基类上定义相同的重载运算符。这样就无需创建包装类型并复制System.Array的所有成员,因为您可以根据需要向上/向下映射同一数组对象。但是,由于基类是无类型的,因此在使用索引访问时,您将失去类型安全性,并且必须对元素进行装箱/拆箱,这非常丑陋:

'T[]