在 F# 中,"do"关键字的一个更微妙的用法是能够注释返回单元(又名语句)的表达式。例如,我经常在函数定义中这样做,以明确返回类型是单位,并指示编译器为我键入 checkthis。例如:
let restart agent = do agent.Post Restart
但是,我不确定 F# 社区中对"do"关键字的主要看法是什么。
在此示例中使用"do"关键字的正确方法是什么:
// Annotate each statement
let move source destination =
do copy source destination
do clear source
// Annotate the statements as one block
let move source destination =
do
copy source destination
clear source
// Just annotate the "return" statement
let move source destination =
copy source destination
do clear source
// Perhaps don't annotate at all?
let move source destination =
copy source destination
clear source
我很少看到 F# 代码中用于此目的do
(引入unit
表达式)。您描述的大多数类型检查已经在没有它的情况下自动执行,以 FS0020 警告的形式提供关于未使用值。
如果你只是写
let move source destination =
copy source destination
clear source
然后会发生以下三件事之一:
copy
和clear
都返回unit
在这种情况下,一切都很好。
copy
返回单位以外的类型在这种情况下,您将收到有关忽略值的 FS0020 警告:
表达式
copy source destination
返回当前被忽略的 int。如果您不需要此值,则应使用 ignore 函数显式忽略它,例如ignore (copy source destination)
或将结果绑定到名称,例如let result = copy source destination
copy
返回单位,clear
返回unit
以外的类型在这种情况下,不会有警告,但
move
将具有与clear
相同的类型,并且这种差异将在呼叫站点上表现出来move
,在那里您将获得与上述相同的警告。
因此,do
用于类型检查目的的效用相当有限:只有在最后一种情况下,它才会有所作为,方法是使警告出现在原始行上,而不是强迫您从move
的呼叫站点导航到它(或者可能 - 如果move
是其范围内的最后一行 - 从move
的呼叫者的呼叫站点, 等等)。这首先很少是一个错误 - 如果clear
返回一个值(例如,指示清除是否成功的布尔值),您肯定希望将该信息传播到调用链上!
也就是说,这是一个非常简单的令牌,(IMO)丝毫不会损害可读性,并且可以说是改进了它。考虑到 F# 社区对少数喜欢禁用轻量级语法 (#light "off"
) 并手动键入分号和end
标记的用户没有问题,我无法想象do
任何地方引起任何关注。