通过引用修改在 lambda 表达式中创建的元组
Modifying tuple created in lambda expression by reference
我在对某个软件进行测试后 运行 试图解析一个非常大的日志文本文件(超过 100 000 行)。为了做到这一点,我将文件分成 1000 行的 windows,并在我们的测试 运行 中为每个测试递增地读取每个 windows。当我读完这 1000 行后,为了确保我不会再无意义地解析它们,我想将布尔值设置为 true,这意味着我应该跳过 window 因为我确定我解析完毕。
这是我到目前为止想出的:
...
let windowedAMLogSeq = Seq.windowed 1000 fullAMLogSeq
|> Seq.map (fun (window:string[]) -> (window , false))
for category in sortedTrxFailedTests do
for failedTest in category do
...
match failedTest.StartTime with
| Some x ->
match failedTest.EndTime with
| Some y ->
let accessManagerLogLines = parseAccessManagerLogFile x y windowedAMLogSeq
...
和
let parseAccessManagerLogFile (testStartTime:DateTime) (testEndTime:DateTime) (windowedAMLogSeq:seq<string[] * bool>) =
Seq.map (parseWindow testStartTime testEndTime) windowedAMLogSeq
和
let parseWindow testStartTime testEndTime (window:(string[] * bool)) =
match (snd window) with
| true ->
[||]
| false ->
let lineArray = Array.map (fun (line:string) -> if (isBetweenStartAndEndTime testStartTime testEndTime line) then line else "") (fst window)
let cleansedArray = Array.partition (fun (line:string) -> line <> "") lineArray
|> fst
match cleansedArray.Length > 0 with
| true ->
()
| false ->
window <- ((fst window), true) // Problem here, not mutable or by ref
cleansedArray
显然,这不会编译,因为 window
不是可变的或通过引用传递的。我尝试了多种使用 mutable 和 ref 或 byref 关键字的组合,但都没有成功。作为 F# 的新手,我不确定要使用的正确语法。
为了直接通过引用修改 window
值,或者能够通过引用修改 window
元组中的布尔值,使用什么语法?
我的问题的解决方案是使用 ref 关键字,如下所示。另外,请注意您现在必须在元组上使用 .Value
属性。
...
let windowedAMLogSeq = Seq.windowed 1000 fullAMLogSeq
|> Seq.map (fun (window:string[]) ->
let mutable tuple = ref (window , false)
tuple
)
for category in sortedTrxFailedTests do
for failedTest in category do
...
match failedTest.StartTime with
| Some x ->
match failedTest.EndTime with
| Some y ->
let accessManagerLogLines = parseAccessManagerLogFile x y windowedAMLogSeq
...
与
let parseAccessManagerLogFile (testStartTime:DateTime) (testEndTime:DateTime) (windowedAMLogSeq:seq<(string[] * bool) ref>) =
Seq.map (parseWindow testStartTime testEndTime) windowedAMLogSeq
和
let parseWindow testStartTime testEndTime (window:(string[] * bool) ref) =
match (snd window.Value) with
| true ->
[||]
| false ->
let lineArray = Array.map (fun (line:string) -> if (isBetweenStartAndEndTime testStartTime testEndTime line) then line else "") (fst window.Value)
let cleansedArray = Array.partition (fun (line:string) -> line <> "") lineArray
|> fst
match cleansedArray.Length > 0 with
| true ->
()
| false ->
window.Value <- ((fst window.Value), true)
cleansedArray
您可以通过将 window 保存在具有可变字段的记录类型中来使整个事情变得更清晰:
type LogWindow =
{
lines: string []
mutable parsed: bool
}
你这样创建它:
let windowedAMLogSeq = Seq.windowed 1000 fullAMLogSeq
|> Seq.map (fun window -> { lines = window; parsed = false })
然后在你的 parseWindow
:
window.parsed <- true
但是我觉得你的代码很奇怪。您真的要创建日志的滑动 windows,而不是将其分成块吗?因为 Seq.windowed
创建的是滑动 windows.
我在对某个软件进行测试后 运行 试图解析一个非常大的日志文本文件(超过 100 000 行)。为了做到这一点,我将文件分成 1000 行的 windows,并在我们的测试 运行 中为每个测试递增地读取每个 windows。当我读完这 1000 行后,为了确保我不会再无意义地解析它们,我想将布尔值设置为 true,这意味着我应该跳过 window 因为我确定我解析完毕。
这是我到目前为止想出的:
...
let windowedAMLogSeq = Seq.windowed 1000 fullAMLogSeq
|> Seq.map (fun (window:string[]) -> (window , false))
for category in sortedTrxFailedTests do
for failedTest in category do
...
match failedTest.StartTime with
| Some x ->
match failedTest.EndTime with
| Some y ->
let accessManagerLogLines = parseAccessManagerLogFile x y windowedAMLogSeq
...
和
let parseAccessManagerLogFile (testStartTime:DateTime) (testEndTime:DateTime) (windowedAMLogSeq:seq<string[] * bool>) =
Seq.map (parseWindow testStartTime testEndTime) windowedAMLogSeq
和
let parseWindow testStartTime testEndTime (window:(string[] * bool)) =
match (snd window) with
| true ->
[||]
| false ->
let lineArray = Array.map (fun (line:string) -> if (isBetweenStartAndEndTime testStartTime testEndTime line) then line else "") (fst window)
let cleansedArray = Array.partition (fun (line:string) -> line <> "") lineArray
|> fst
match cleansedArray.Length > 0 with
| true ->
()
| false ->
window <- ((fst window), true) // Problem here, not mutable or by ref
cleansedArray
显然,这不会编译,因为 window
不是可变的或通过引用传递的。我尝试了多种使用 mutable 和 ref 或 byref 关键字的组合,但都没有成功。作为 F# 的新手,我不确定要使用的正确语法。
为了直接通过引用修改 window
值,或者能够通过引用修改 window
元组中的布尔值,使用什么语法?
我的问题的解决方案是使用 ref 关键字,如下所示。另外,请注意您现在必须在元组上使用 .Value
属性。
...
let windowedAMLogSeq = Seq.windowed 1000 fullAMLogSeq
|> Seq.map (fun (window:string[]) ->
let mutable tuple = ref (window , false)
tuple
)
for category in sortedTrxFailedTests do
for failedTest in category do
...
match failedTest.StartTime with
| Some x ->
match failedTest.EndTime with
| Some y ->
let accessManagerLogLines = parseAccessManagerLogFile x y windowedAMLogSeq
...
与
let parseAccessManagerLogFile (testStartTime:DateTime) (testEndTime:DateTime) (windowedAMLogSeq:seq<(string[] * bool) ref>) =
Seq.map (parseWindow testStartTime testEndTime) windowedAMLogSeq
和
let parseWindow testStartTime testEndTime (window:(string[] * bool) ref) =
match (snd window.Value) with
| true ->
[||]
| false ->
let lineArray = Array.map (fun (line:string) -> if (isBetweenStartAndEndTime testStartTime testEndTime line) then line else "") (fst window.Value)
let cleansedArray = Array.partition (fun (line:string) -> line <> "") lineArray
|> fst
match cleansedArray.Length > 0 with
| true ->
()
| false ->
window.Value <- ((fst window.Value), true)
cleansedArray
您可以通过将 window 保存在具有可变字段的记录类型中来使整个事情变得更清晰:
type LogWindow =
{
lines: string []
mutable parsed: bool
}
你这样创建它:
let windowedAMLogSeq = Seq.windowed 1000 fullAMLogSeq
|> Seq.map (fun window -> { lines = window; parsed = false })
然后在你的 parseWindow
:
window.parsed <- true
但是我觉得你的代码很奇怪。您真的要创建日志的滑动 windows,而不是将其分成块吗?因为 Seq.windowed
创建的是滑动 windows.