用序列包装可变集合

时间:2011-07-07 02:40:21

标签: collections f# ienumerable

偶尔,我想从函数中返回一个可变集合作为序列。上传到seq<_>有效,但序列可以被下调和修改(通常不重要)。我通常的解决方案是使用wrap-as-a-sequence函数,它产生了以下结果:

let wrap items = Seq.map id
let wrapDict dict = Seq.map ((|KeyValue|) >> snd)

主要是出于好奇(和乐趣),编写这些函数的其他方式是什么,可能是以更惯用,更简洁或更有效的方式?

2 个答案:

答案 0 :(得分:5)

Seq.readonly是您正在寻找的功能。

答案 1 :(得分:2)

我认为Stephan建议的功能可能就是你要找的东西。

然而,有一件棘手的事情 - Seq.readonly函数(以及ReadOnlyCollection或使用Seq.map)包装序列,以便它不能从外部变异。但是,它仍然具有非常微妙的行为,因为结果序列可以被对象突变:

type Arr() = 
    let data = [| 1 .. 5 |]
    member x.ItemsSeq = Seq.readonly data
    member x.Mutate() = data.[0] <- 10

let a = Arr()
let s = a.ItemsSeq
printfn "%A" (s |> List.ofSeq) // [1; 2; 3; 4; 5]
a.Mutate()
printfn "%A" (s |> List.ofSeq) // [10; 2; 3; 4; 5]

我认为这是一种非常意外的行为(在一种主要是功能性的语言中)。

因此,如果内部集合是可变的,您还可以考虑创建一个以后无法修改的数据的完整克隆,并保证返回的序列始终提供相同的结果。例如,使用data |> Array.ofSeq |> Seq.readonly