数组切片的奇怪行为

时间:2012-04-22 15:37:56

标签: arrays f# slice

> 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 个答案:

答案 0 :(得分:5)

这是一个错误。

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

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

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

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,我们在len = 0中有GetArraySubzeroCreate 0会返回一个空数组。 finish - start <= -2导致len < 0zeroCreate len失败的情况不再如此。

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