使用Array.iter时,为什么我的F#函数会导致越界错误?

时间:2016-04-18 17:12:42

标签: .net arrays f#

我有一个函数,其中Array.iter用于在应用函数后打印嵌套数组的第4个元素(z)。我正在喂一条由' \ n'划分的长串。然后(嵌套)划分'"'。它似乎迭代到更高级别数组(y)的末尾。

let digestMDtest (x : string) =
    let y = x.Split '\n' |> Array.tail
    let mapMD (x : string) =
        let z = x.Split '"'
        printfn "%s" z.[3]
    Array.iter mapMD y

我收到错误,你可以看到最后3个时间戳是我所参与的数据的一部分," 2016-04-15T15:59:00-04:00"是最后一个元素,它似乎超越了它。

2016-04-15T15:57:00-04:00
2016-04-15T15:58:00-04:00
2016-04-15T15:59:00-04:00
System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at FSI_0002.mapMD@69-1(String x) in C:\OneDrive\FSMDC.barchart.fsx:line 70
   at FSI_0002.digestMDtest(String x) in C:\OneDrive\FMDC.barchart.fsx:line 72

在我看来,Array.iter函数正在尝试迭代超出数组末尾的Array元素。它为什么要这样做?我只能假设Array.tai​​l与它有关;也许Array.iter正在使用数组的原始大小而不是当前大小?

2 个答案:

答案 0 :(得分:4)

鉴于您对输入数据的书面描述,我创建了一个这样的示例设置(如果我误解了您的描述,请告诉我!):

let data = "\"2016-04-15T15:57:00-04:00\"\n\"2016-04-15T15:58:00-04:00\"\n\"2016-04-15T15:59:00-04:00\""

假设我的数据与您的数据大致匹配,您将跳过第一个值,然后Array.iter超过其余两个值:

"2016-04-15T15:58:00-04:00"
"2016-04-15T15:59:00-04:00"

然后在每个元素上调用此函数:

let mapMD (x : string) =
    let z = x.Split '"'
    printfn "%s" z.[3]

在这些字符串上调用Split会得到如下结果:

[|"", date, ""|]

您从此数组索引元素.[3],但只有3个元素,因此这将在每个元素上触发IndexOutOfRangeException

索引元素一般来说在函数式编程中不是一个好模式,使用一种模式,你可以使意图更明确,通常更好。

举个例子,如果我在这种情况下尝试提取日期字符串,我会这样做:

let mapMD (x : string) =
    match x.Split '"' with
    |[|_; date; _|] -> printfn "%s" date
    |_ -> raise <| FormatException("Invalid Date String Format")

您可以在这里看到,模式匹配简明扼要地描述了字符串数组的预期格式。

答案 1 :(得分:2)

IndexOutOfRange异常与Array.iter无关,而是与索引到另一个数组 - 特别是在第70行,表达式z.[3]

显然,您的行有少于四个以引号分隔的部分。

作为旁注,我建议分别使用Seq.skipSeq.iter代替Array.tailArray.iterArray.tail调用将重新分配一个全新的数组,这可能会变得昂贵。

let digestMDtest (x : string) =
    x.Split '\n' 
    |> Seq.skip 1
    |> Seq.iter (fun (x : string) ->
        let z = x.Split '"'
        printfn "%s" z.[3] )