f# - 使用 bigint 查找扩展 F# 数组
问题描述
我想扩展 F# 数组,这样我就可以使用数组而不转换为有限的int
. 相反,我想bigint
直接使用。
我能够向数组类型添加第二个长度方法,如下所示:
type 'T ``[]`` with
member this.LengthI: bigint =
bigint this.Length
member this.Item(index: bigint): 'T =
this.[int index]
但是,Item
无法使用.[ ]
语法调用该方法。
有什么想法可以实现吗?我这可能吗?
解决方案
我强烈怀疑这对于本机数组是不可能的。您可以验证自己是否可以为其他集合重载索引访问。
如果编译以下代码:
let myArray = [| "a" |]
let myList = [ "a" ]
let arrayElement = myArray.[11111]
let listElement = myList.[22222]
并检查生成的 IL,您会看到在访问列表元素时编译为常规虚拟调用,有一个特殊的 CIL 指令用于访问本机数组元素,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[]
,因为您可以根据需要向上/向下转换相同的数组对象。但是,由于基类是无类型的,因此您将失去类型安全性,并且在使用索引访问时必须对元素进行装箱/拆箱,这非常难看:
type System.Array with
member this.Item
with get (index : int) = (this :?> 'T[]).[index]
and set (index : int) (value : 'T) = (this :?> 'T[]).[index] <- value
member this.Item
with get(index : bigint) : 'T = (this :?> 'T[]).[int index]
and set(index : bigint) (value : 'T) = (this :?> 'T[]).[int index] <- value
let untypedArray = myArray :> System.Array
let untypedArrayElement = box untypedArray.[0] :?> string
let untypedArrayElement2 = box untypedArray.[bigint 0] :?> string
推荐阅读
- .htaccess - 我想做 301 重定向但它出错了
- reactjs - React Security 关于状态管理
- python - Python程序文件移动减慢进程/使异步文件移动?
- javascript - 交叉点观察者在轮播 (Siema) 上循环后“卸载”图像
- mongodb - 从 MongoDB 中的两个集合中查询
- python - 你可以跳过python中for循环的下一次迭代吗?
- java - 如何使用 gradle 构建包含多个 java 模块的单个 jar 文件?
- python - 重新加载对象的@property-decorated 方法
- r - 如何在ar循环中运行函数
- javascript - html2canvas 中的文字只显示一行