数组切片的奇怪行为

qeh*_*hgt 6 arrays f# slice

> let a = [| 'a'..'d' |];;
val a : char [] = [|'a'; 'b'; 'c'; 'd'|]
Run Code Online (Sandbox Code Playgroud)

做琐碎的切片:

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

现在尝试使用空白区域:

> a.[1..0], [1..0];;
val it : char [] * int list = ([||], [])
Run Code Online (Sandbox Code Playgroud)

似乎工作和合理 - 我们有两个空序列.

但它失败了:

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

当然,有一种解决方法[| for i in [5..0] -> a.[i] |].但我想念a.[5..0]失败的原因?为什么不直接返回空数组?这种行为有什么理由吗?

pad*_*pad 5

这是一个错误.

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

请注意,异常发生在a.[start..finish]when finish - start <= -2(a.[3..1]失败)和数组切片工作正常if finish - start = -1(a.[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)
Run Code Online (Sandbox Code Playgroud)

虽然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
Run Code Online (Sandbox Code Playgroud)

如果finish - start = -1,我们len = 0进入GetArraySubzeroCreate 0返回一个空数组.它不再是finish - start <= -2导致len < 0zeroCreate len失败的情况.

这可以通过始终返回空数组来解决finish - start <= -1.