我想扩展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]
方法。
任何想法如何实现?我有可能吗?
答案 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[]