考虑一下:
module Module1 =
type A() = class end
type B() = inherit A()
type C() = inherit A()
let f x = if x > 0 then new B() else new C()
最后一行产生关于预期类型B的错误,但是找到了类型C.好吧,我可以假装理解:编译器不知道在有多少公共基础的情况下推断出来 .
但猜猜怎么了?即使我指定了函数类型,它仍然不起作用:
let f x : A = if x > 0 then new B() else new C()
现在这给了我两个错误:“A预期,B找到" and " A预期,C找到” . WTF?为什么不能看到B和C都可以隐式转换为A?
是的,我知道我可以使用 upcast
,就像这样:
let f x : A = if x > 0 then upcast new B() else upcast new C()
但猜猜(又一次)? upcast
仅在显式函数类型声明的情况下有效!换句话说,这个:
let f x = if x > 0 then upcast new B() else upcast new C()
仍然给出错误 .
WTF?为了帮助编译器,我真的必须在程序中添加50%的噪音吗?关于F#代码干净无噪音的炒作是什么?
不知怎的,感觉这不可能是真的 . 所以问题是:我错过了什么吗?如何使这既紧凑又有效?
2 回答
所有这一切都有一个原因,但要缩短:F#比C#更强大,所以你必须告诉在哪里投(见here):
在这里您可以找到更多信息:F# need for cast
这是另一个伟大的discussion .
类型推断和子类型不能很好地结合在一起,因为Carsten的链接在某种程度上进行了讨论 . 听起来你对F#的方法不满意,如果是的话会更喜欢它
被隐含地对待更像
与编译器另外推断
'a
是类型层次结构中的最小上限,基于否则将推断e1
和e2
的类型 .在技术上可能这样做,我可以这样工作,但是这里有一个猜测:如果
if
语句以这种方式运行,那么在if
和else
分支中使用不同类型永远不会出错,因为它们可以总是通过隐式地将它们向上转换为obj
来统一 . 但是,在实践中,这几乎总是一个程序员错误 - 你几乎总是希望类型是相同的(例如,如果我从一个分支返回一个字符而另一个字符串返回一个字符串,我可能意味着从两个字符串返回字符串,而不是obj
) . 通过隐式向上转换,您只会更难找到这些错误 .此外,它正在寻找比
upcast
语法更短的解决方案,您可以尝试使用:> _
,只要存在约束类型的东西(整体结果上的注释或其中一个分支上的特定强制转换) ) .