F#:Downcast seq to IEnumerator

Mil*_*oDC 4 ienumerator f# seq

为什么在F#中,我可以这样做......

let s = seq { for i in 0 .. 4095 do yield i } :?> IEnumerator
Run Code Online (Sandbox Code Playgroud)

......但这会抛出一个System.InvalidCastException

let s = Seq.init 4095 (fun i -> i) :?> IEnumerator
Run Code Online (Sandbox Code Playgroud)

p.s*_*w.g 6

序列表达式创建一个实现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
Run Code Online (Sandbox Code Playgroud)

Seq.init不是:

let s = Seq.init 4095 (fun i -> i)
printfn "%b" (s :? IEnumerable<int>) // true
printfn "%b" (s :? IEnumerator<int>) // false
Run Code Online (Sandbox Code Playgroud)

你可以重构你的代码IEnumerable<T>而不是IEnumerator因为两个结构都产生了IEnumerable<T>.

或者,如果你真的想要的IEnumerator,你可以简单地调用GetEnumerator返回的EnumeratorEnumerable:

let s = (Seq.init 4095 (fun i -> i)).GetEnumerator()
printfn "%b" (s :? IEnumerable<int>) // false
printfn "%b" (s :? IEnumerator<int>) // true
Run Code Online (Sandbox Code Playgroud)


Lee*_*Lee 5

如果查看规范,序列表达式将转换为:

Seq.collect (fun pat -> Seq.singleton(pat)) (0 .. 4095)
Run Code Online (Sandbox Code Playgroud)

如果你看一下Seq.collect它的定义来源是:

let collect f sources = map f sources |> concat
Run Code Online (Sandbox Code Playgroud)

如果你看concat它的定义是:

let concat sources = 
            checkNonNull "sources" sources
            mkConcatSeq sources
Run Code Online (Sandbox Code Playgroud)

mkConcatSeq 定义为:

let mkConcatSeq (sources: seq<'U :> seq<'T>>) = 
            mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>)
Run Code Online (Sandbox Code Playgroud)

所以你可以看到返回的序列实现了IEnumerator<'T>,因此IEnumerator.

现在Seq.init定义为:

let init count f =
            if count < 0 then invalidArg "count" (SR.GetString(SR.inputMustBeNonNegative))
            mkSeq (fun () -> IEnumerator.upto (Some (count-1)) f)
Run Code Online (Sandbox Code Playgroud)

mkSeq定义为:

let mkSeq f = 
            { new IEnumerable<'U> with 
                member x.GetEnumerator() = f()
              interface IEnumerable with 
                member x.GetEnumerator() = (f() :> IEnumerator) }
Run Code Online (Sandbox Code Playgroud)

所以它只实现IEnumerable<'T>而不是IEnumerator.