我知道我必须遗漏一些非常明显的东西.B.GetInstance().Call()生成错误:根据此程序点之前的信息查找不确定类型的对象.在此程序点之前可能需要类型注释来约束对象的类型.这可以允许解析查找.
我正在使用v1.9.9.9.
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() = new B()
member x.Call() = ()
Run Code Online (Sandbox Code Playgroud)
我刚刚发现这个有效: (B.GetInstance() :> B).Call()
知道为什么演员是必要的吗?
通常,当你有一个递归的方法集来推断其类型时,F#需要帮助.一个更令人愉快的选择是注释定义B.GetInstance:
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() : B = new B()
member x.Call() = ()
Run Code Online (Sandbox Code Playgroud)
我相信你遇到这个问题的原因是F#试图同时解决A和B中所有方法的所有推断类型(因为它们被定义为相互递归类型),这会导致问题,但也许是来自F#的人团队将权衡.
快速摘要是在一个递归组中(例如,一种类型的成员,或者像我们这里一样的递归类型的成员)F#以从左到右的从上到下的顺序读取声明,然后是左边的定义 -从右到上的顺序.因此,在这个实例中,当它达到定义时A.Call,它还没有读取定义,B.GetInstance因此(但是!)知道返回类型GetInstance将是B.
Keith的回答指出了这种情况,你可以提供一个类型注释来指定GetInstance其声明中的返回类型.
看到
深入讨论这里发生了什么.
另请注意,在原始尝试中,您不需要"强制转换"(使用潜在的动态操作:>),而只需"注释"(静态声明类型,使用:)以使其进行编译.但更有意义的是将类型注释放在方法声明中GetInstance(通常,更喜欢对方法签名添加注释而不是在主体内部的任意位置).