con*_*low 2 compiler-construction ienumerable f# for-loop
open System
type Foo() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
type Bar() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
interface Collections.Generic.IEnumerable<int> with
member x.GetEnumerator () = null
let xs, ys = Foo(), Bar()
for x in xs do () // <--
for y in ys do () // fine
Run Code Online (Sandbox Code Playgroud)
上面的代码产生以下编译错误:
The type 'Foo' is not a type whose values can be enumerated with this syntax, i.e. is not compatible with either seq<_>, IEnumerable<_> or IEnumerable and does not have a GetEnumerator method.
代码看起来完全合法,通用版本工作正常.这是一个F#编译器错误吗?
我认为这是错误消息和规范之间的不匹配.正如kvb指出的那样,规范for ... in只允许两种情况:
IEnumerable<_>接口(又名seq<_>)GetEnumerator返回具有某些属性的类型的方法时如果类型实现非泛型IEnumerable接口,则它不匹配任何两个条件.但是,如果你把它投射到IEnumerable那么它实际上是IEnumerable类型,它匹配第二个条件.GetEnumerator直接在类型中有成员(如desco建议的那样)也是正确的,因为它也匹配第二种情况.
所以,我认为错误消息是不正确的,因为它表示实现非泛型IEnumerable就足够了,但实际上并非如此.
但是,似乎有一个与for循环相关的实际编译器错误.编写以下代码时会出现编译器"内部错误"(这是不正确的,因为推断的泛型返回类型没有实现IEnumerator):
type Foo() =
member x.GetEnumerator () = null
for x in Foo() do () // Internal error here
Run Code Online (Sandbox Code Playgroud)
您的样本可以简化为
type Foo() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
for x in Foo() do ()
Run Code Online (Sandbox Code Playgroud)
最初,F#编译器尝试断言源类型正在实现IEnumerable <_>在此断言失败后 - 它搜索可访问的GetEnumerator/0方法,该方法返回具有可访问的MoveNext()/ Current成员的类型.似乎来自IEnumerable的显式实现的方法在Foo类型中是不可见的,因为下面的代码是有效的:
open System
open System.Collections
type Foo() =
member x.GetEnumerator () : IEnumerator = null
for x in Foo() do () // GetEnumerator is accessible in Foo
Run Code Online (Sandbox Code Playgroud)
要么
open System
open System.Collections
type Foo() =
interface IEnumerable with
member x.GetEnumerator () : IEnumerator = null
for x in (Foo() :> IEnumerable) do () // IEnumerable has accessible GetEnumerator
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
249 次 |
| 最近记录: |