通配符“使用”绑定在序列表达式中起作用,但不起作用

时间:2011-12-08 22:58:40

标签: f#

使用带有use的通配符模式在序列表达式中起作用,但不是这样。有这个原因吗?

let mkDisposable() = 
  { new IDisposable with 
      member __.Dispose() = () }

let mkSeq() =  
  seq {
    use _ = mkDisposable() //OK
    ()
  }

let f() =  
  use _ = mkDisposable() //ERROR: 'use' bindings must be of the form 'use <var> = <expr>'
  ()

2 个答案:

答案 0 :(得分:2)

我认为这是计算表达式(在这种情况下是一个序列表达式,但这种行为适用于所有计算表达式)的自然(但意外)后果。 As the spec indicates

use pat = expr
cexpr

被翻译为

Using(expr, fun pat -> cepxr)

因为这是一个浅层的句法翻译,你可以使用编写函数时可以使用的任何模式,包括_。但是,对于正常use绑定,绑定的左侧必须是标识符,而不是模式(请参阅section 6.6.3 of the spec)。< / p>

答案 1 :(得分:1)

我已经做了一些挖掘,似乎处理特殊方式seq表达式会改变use的规则。 seq表达式实际上已转换为以下IDisposable字段,该字段在序列完成时处理。

internal sealed class mkSeq@11<a> : GeneratedSequenceBase<a>
{
    [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
    public IDisposable matchValue = matchValue;
    [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
    public int pc = pc;
    [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
    public a current = current;
    public mkSeq@11(IDisposable matchValue, int pc, a current)
    {
    }
    public override int GenerateNext(ref IEnumerable<a> next)
    {
        switch (this.pc)
        {
            case 2:
            {
                break;
            }
            case 3:
            {
                goto IL_55;
            }
            default:
            {
                this.matchValue = Program.mkDisposable();
                this.pc = 2;
                break;
            }
        }
        this.pc = 3;
        LanguagePrimitives.IntrinsicFunctions.Dispose<IDisposable>(this.matchValue);
        this.matchValue = null;
        this.pc = 3;
        IL_55:
        this.current = default(a);
        return 0;
    }
    public override void Close()
    {
        switch (this.pc)
        {
            case 1:
            {
                goto IL_41;
            }
            case 3:
            {
                goto IL_41;
            }
        }
        this.pc = 3;
        LanguagePrimitives.IntrinsicFunctions.Dispose<IDisposable>(this.matchValue);
        IL_41:
        this.pc = 3;
        this.current = default(a);
    }
    public override bool get_CheckClose()
    {
        switch (this.pc)
        {
            case 1:
            {
                return false;
            }
            case 3:
            {
                return false;
            }
        }
        return true;
    }
    [CompilerGenerated, DebuggerNonUserCode]
    public override a get_LastGenerated()
    {
        return this.current;
    }
    [CompilerGenerated, DebuggerNonUserCode]
    public override IEnumerator<a> GetFreshEnumerator()
    {
        return new Program<a>.mkSeq@11(null, 0, default(a));
    }
}

通常use转换为:

IDisposable e = Program.mkDisposable();
try
{
}
finally
{
    IDisposable disposable = e as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}

如果没有变量名,编译器将忽略表达式的结果,因此无法处理它。说实话,似乎应该为use做一个特殊情况,所以所有样板都是在幕后创建的,就像我们在seq表达式中看到的那样。