Wrapping a mutable collection with a sequence
Occasionally, I want to return a mutable collection from a function as a sequence. Upcasting to seq<_>
works, but the sequence could be downcasted and modified (not that it usually matters开发者_如何学编程). My usual solution is to use a wrap-as-a-sequence function which has given rise to the following:
let wrap items = Seq.map id
let wrapDict dict = Seq.map ((|KeyValue|) >> snd)
Mostly for curiosity (and fun), what would be other ways of writing such functions, perhaps in a more idiomatic, concise, or performant way?
Seq.readonly is the function you are looking for.
I think that the function suggested by Stephan is probably the thing you're looking for.
However, there is one tricky thing - the Seq.readonly
function (as well as ReadOnlyCollection
or using Seq.map
) wraps the sequence so that it cannot be mutated from the outside. However, it still has quite subtle behavior because the resulting sequence can be mutated by the object:
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]
I would think that this is quite unexpected behavior (in a mostly functional language).
So, if the internal collection is mutable, you may also consider creating a complete clone of the data that cannot be modified later and guarantees that the returned sequence will always give the same results. For example using data |> Array.ofSeq |> Seq.readonly
精彩评论