数组切片的奇怪行为

6
> let a = [| 'a'..'d' |];;
val a : char [] = [|'a'; 'b'; 'c'; 'd'|]

进行细微的切片:

> a.[1..2], [1..2];;
val it : char [] * int list = ([|'b'; 'c'|], [1; 2])

现在尝试使用空区域:
> a.[1..0], [1..0];;
val it : char [] * int list = ([||], [])

看起来工作得很好,也很合理 - 我们获得了两个空序列。

但是在这里它失败了:

> a.[5..0];;
System.OverflowException: Arithmetic operation resulted in an overflow.
   at <StartupCode$FSI_0018>.$FSI_0018.main@()
Stopped due to error

当然,有一种解决方法是使用 [| for i in [5..0] -> a.[i] |]。但是,我不明白为什么 a.[5..0] 会失败?为什么不能返回一个空数组呢?这种行为有任何原因吗?
1个回答

5

这是一个错误。

虽然数组切片和范围表达式是不同的概念(例如,您不能使用a.[1..2..5]),但它们应该保持一致的行为。

请注意,当finish - start <= -2时(a.[3..1]失败),a.[start..finish]会发生异常,而如果finish - start = -1a.[5..4] = [||]),则数组切片可以正常工作。

使用prim-types.fs中的GetArraySlice函数进行数组切片:

let inline GetArraySlice (arr: _[]) start finish = 
    let start  = (match start with None -> 0 | Some n -> n) 
    let finish = (match finish with None -> arr.Length - 1 | Some n -> n) 
    GetArraySub arr start (finish - start + 1)

GetArraySub则在同一模块中实现,代码如下:

let inline GetArraySub arr (start:int) (len:int) =
    let dst = zeroCreate len   
    for i = 0 to len - 1 do 
        SetArray dst i (GetArray arr (start + i))
    dst

如果finish - start = -1,那么在GetArraySub中我们有len = 0,并且zeroCreate 0返回一个空数组。但是当finish - start <= -2时,情况就不同了,这会导致len < 0zeroCreate len失败。
通过始终在finish - start <= -1时返回一个空数组,可以解决这个问题。

你知道 F# 的“官方”错误跟踪器在哪里吗? - qehgt
1
您可以将错误报告发送至 fsbugs (at) microsoft (dot) com。 - pad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接