F# spec在模块中的 10.2.5 do
语句中描述,在模块级别上do
语句可能具有属性,并且它将生成当表达式的类型未计算为unit
时的警告。显然,do
语句在其他位置的行为类似于Block表达式( 6.5.1 ),无论是括号还是开始结束,同时仍然断言{ {1}}输入。
这使得unit
语句适合控制确定性处置表达式的范围( 6.6.4 ):
do
如果规范中没有明确说明,还有什么能阻止F#编译器的维护人员破坏这种用法吗?
答案 0 :(得分:2)
我认为示例中的aba
函数实际上同时使用了do
语句和块表达式。 do
的语法是do <expr>
,因此do
语句的主体是单个表达式。如果我们用括号写相同的东西:
let aba() =
use a = d "a"
do ( use b = d "b"
printf "a + b, " )
printf "a, "
确定性处置行为然后来自块表达式的通常确定性处置行为 - 而不是来自do
块的一些未记录的属性。
答案 1 :(得分:0)
这里根本不需要do
语句,使用括号就足够了:
let aba() =
use a = d "a"
(
use b = d "b"
printf "a + b, "
)
printf "a, "
aba(); printfn ""
// Prints "new a, new b, a + b, disposing b, a, disposing a, "
这是Tomas Petricek的例子减去do
。括号为它们包含的代码块定义了一个新范围,因此当您到达右括号时,b
超出范围并被处置。为了证明范围规则是这样的,让我们添加另一个变量定义:
let aba() =
use a = d "a"
(
use b = d "b"
let c = 5
printf "a + b, and c=%d " c // This compiles
)
printf "and now c=%d " c // This does not compile
printf "a, "
aba(); printfn ""
括号内的c
的第一次使用将被编译。括号外的c
的第二次使用将无法编译,因为此时c
超出了范围,您将获得:
错误FS0039:未定义值或构造函数“c”。
因此,如果您正在使用do
表达式来控制IDisposable
何时超出范围,则可以仅使用括号来实现相同的结果。由您决定哪种形式更具可读性。