爲什麼在F#中,我能做到這一點...F#:低迷現狀,以次來的IEnumerator
let s = seq { for i in 0 .. 4095 do yield i } :?> IEnumerator
...但是這將引發System.InvalidCastException
?
let s = Seq.init 4095 (fun i -> i) :?> IEnumerator
爲什麼在F#中,我能做到這一點...F#:低迷現狀,以次來的IEnumerator
let s = seq { for i in 0 .. 4095 do yield i } :?> IEnumerator
...但是這將引發System.InvalidCastException
?
let s = Seq.init 4095 (fun i -> i) :?> IEnumerator
序列表達式創建了一個實現IEnumerable<T>
和IEnumerator<T>
let s = seq { for i in 0 .. 4095 do yield i }
printfn "%b" (s :? IEnumerable<int>) // true
printfn "%b" (s :? IEnumerator<int>) // true
但Seq.init
對象不:
let s = Seq.init 4095 (fun i -> i)
printfn "%b" (s :? IEnumerable<int>) // true
printfn "%b" (s :? IEnumerator<int>) // false
您可以重構代碼以使用IEnumerable<T>
而不是IEnumerator
因爲兩個構造產生一個IEnumerable<T>
。
或者,如果你真的想要一個IEnumerator
,你可以簡單地調用GetEnumerator
返回一個Enumerator
從Enumerable
:
let s = (Seq.init 4095 (fun i -> i)).GetEnumerator()
printfn "%b" (s :? IEnumerable<int>) // false
printfn "%b" (s :? IEnumerator<int>) // true
當,偷走了我的答案。好吧,其中的一部分......不知道序列表達式與Seq模塊的對應表達式並不完全相同。 – Jwosty
如果你看一下the specification,你序列表達式轉換爲:
Seq.collect (fun pat -> Seq.singleton(pat)) (0 .. 4095)
如果你看看Seq.collect
的定義來源,它是:
let collect f sources = map f sources |> concat
,如果你看一下定義concat
是:
let concat sources =
checkNonNull "sources" sources
mkConcatSeq sources
mkConcatSeq
被定義爲:
let mkConcatSeq (sources: seq<'U :> seq<'T>>) =
mkSeq (fun() -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>)
所以你可以看到,返回的序列實現IEnumerator<'T>
,因此IEnumerator
。
let init count f =
if count < 0 then invalidArg "count" (SR.GetString(SR.inputMustBeNonNegative))
mkSeq (fun() -> IEnumerator.upto (Some (count-1)) f)
和mkSeq
定義爲:
let mkSeq f =
{ new IEnumerable<'U> with
member x.GetEnumerator() = f()
interface IEnumerable with
member x.GetEnumerator() = (f() :> IEnumerator) }
所以它僅實現IEnumerable<'T>
,而不是IEnumerator
因爲現在Seq.init
定義。
你確定你不想IEnumerable而不是IEnumerator? – ildjarn
我正在爲Unity編寫協程。必須是IEnumerator。 – MiloDC