【问题标题】:What is exactly lvalue context in Rust?Rust 中的左值上下文到底是什么?
【发布时间】:2017-07-07 19:11:55
【问题描述】:

根据the documentation,我们有左值和右值上下文。我如何知道表达式是否在左值上下文中?它是否仅由赋值中的表达式一侧确定?

更具体地说,我需要了解 DerefMut 何时用于取消引用以及何时使用 Deref?与IndexIndexMut 相同。

【问题讨论】:

  • 文档的下两段似乎回答了您的问题。特别是: 赋值或复合赋值表达式的左操作数是左值上下文,一元借位的单个操作数也是如此。如果进行了 ref 绑定,则匹配表达式的判别式或主题可能是左值上下文,否则是右值上下文。所有其他表达式上下文都是右值上下文。

标签: rust type-inference


【解决方案1】:

您在这里提出了两个不同的问题。

更具体地说,我需要了解,何时使用DerefMut 进行取消引用,何时使用Deref?与IndexIndexMut 相同。

这仅取决于结果值是否可变使用。使用属于这些特征的运算符([]*)的表达式始终是左值表达式


现在你的问题更复杂:

我如何知道表达式是否在左值上下文中?它是否仅由赋值中的表达式一侧确定?

表达类别

回顾一下:什么是右值/左值表达式

  • 右值表达式表示一个值
  • 左值表达式表示内存位置中的值(或者换句话说:表示存在某处/有家的值)

哪些表达式是左值表达式,哪些是右值表达式?只有几个l值表达式:

  • “名称”(或者更确切地说:路径)引用变量(本地、函数参数或静态)
  • 索引表达式(例如foo[3]
  • deref 表达式(例如*foo
  • 字段访问表达式(例如foo.bar

上下文类别

右值/左值上下文呢?这些上下文是表达式内部的“槽”。例如,表达式“模”(%)有两个槽,第一个和第二个操作数:⟨first⟩ % ⟨second⟩。现在这些上下文也有两种不同的风格:

  • 右值上下文是一个“槽”,其中需要一个值
  • 左值上下文是一个“槽”,需要一个内存位置

那么哪些槽是右值,哪些是左值上下文?幸运的是,l值上下文的数量非常有限,所以这里有一个完整的列表:

  • (复合)赋值的左侧(例如 ⟨lvalue context⟩ = ...;⟨lvalue context⟩ += ...;
  • 一元借位的操作数(&⟨lvalue context⟩&mut ⟨lvalue context⟩
  • 当某物绑定到出现ref 的模式时(例如let ref x = &⟨lvalue context⟩;

在上下文 Y 中使用表达式 X

让我们看看我们可以在哪些上下文中使用哪些表达式

  • [R in R] rr值上下文中的值表达式:没问题,表达式用作值(例如,赋值右侧的文字3
  • [L in L] ll值上下文中的值表达式:没问题,表达式用作内存位置(例如,赋值左侧的变量名)
  • [L in R] lr值上下文中的值表达式:因为context 需要一个值,而表达式表示“内存位置中的值”,我们可以只使用表达式的值。所以:一切都很好(例如,赋值右侧的变量名)。所以我们可以看到:左值表达式右值表达式更有价值。
  • [R in L] rl值上下文中的值表达式:这里是它变得有问题的地方。上下文需要一个内存地址,但表达式只表示一个值。有时,Rust 会进行“右值提升”以使这种情况发挥作用。这意味着 Rust 会自动将表达式的值放入新的内存位置(临时变量)并在上下文中使用该位置。例如,&mut 3 因上述促销而起作用。此促销目前不适用于 seems to be a bug in either the documentation or the compiler 的作业。

【讨论】:

    【解决方案2】:

    DerefMut/Deref/Index/IndexMutmutability 决定,这是一个与 lvalue/rvalue context 不同的问题。可变性对右值上下文没有意义。

    事实上,所有四个特征都要求操作数 self 在左值上下文中,因为它们都将 &Self&mut Self 作为参数。

    DerefMut/IndexMut 在需要可变性时使用,例如

    *here = ...;
    here[i] = ...;
    
    &mut here
    &mut here[i]
    
    here.call_some_mut_method(...)
    here[i].call_some_mut_method(...)
    

    左值上下文是您想知道表达式的地址(内存位置/引用/...)的地方,而不是它的值。需要左值的地方。

    赋值或复合赋值表达式的左操作数是左值上下文,...

    here = ...;
    
    here += ...;
    

    ... 一元借位的单个操作数也是如此。

    &here
    
    &mut here
    
    let ref ... = here;
    // Note: equivalent to `let ... = &here;`
    
    let ref mut ... = here;
    // Note: equivalent to `let ... = &mut here;`
    

    注意:这显示了一个不可变的左值上下文

    如果进行了 ref 绑定,则匹配表达式的判别式或主题可能是左值上下文,否则为右值上下文。

    match here {
        Ok(ref ...) => ...,
        Err(ref mut ...) => ...,
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-26
      • 2011-07-21
      • 2020-10-06
      • 2012-03-12
      • 2013-05-29
      • 2011-04-24
      • 2022-11-22
      相关资源
      最近更新 更多