为什么允许分配给临时数据成员?

nic*_*lai 4 rust

为什么允许以下代码片段中的分配?

#[derive(Copy, Clone)]
pub struct X {
    pub a: u8,
}

fn main() {
    let x = X { a: 0 };
    { x }.a = 5;
    assert!(x.a == 5); // I was wrong
}
Run Code Online (Sandbox Code Playgroud)

我分配给临时工吗?

尽管这些是被禁止的:

({ x.a }) = 5;
let mut y: u8 = 0;
({ y }) = 5;
Run Code Online (Sandbox Code Playgroud)

我问,因为我有一个像这样的错误

unsafe { *some_struct }.mem1 = 5;
Run Code Online (Sandbox Code Playgroud)

我没用过

unsafe { *some_struct.mem1 = 5; }
Run Code Online (Sandbox Code Playgroud)

从一开始,因为让不安全块尽可能短感觉是正确的。

Bam*_*tan 5

是的,您正在分配给临时对象,因为 X 实现了 Copy,因此{ x }您正在创建一个返回 x 的块,但 X 实现了 Copy,因此您的块返回 x 的副本。你的块基本上是这样的:

#[derive(Copy, Clone)]
pub struct X {
    pub a: u8,
}

fn main() {
    let x = X { a: 0 };
    let mut tmp = { x };
    tmp.a = 5;
    assert_eq(x.a, 0);
    assert_eq!(tmp.a, 5);
}
Run Code Online (Sandbox Code Playgroud)

要使块返回实际变量而不是副本,您可以做的是将指针转换为可变引用,并从不安全块返回该引用:

#[derive(Copy, Clone)]
pub struct X {
    pub a: u8,
}

fn main() {
    let mut x = X { a: 0 };
    let ptr: *mut X = &mut x;

    unsafe {
        &mut *ptr
    }.a = 5;
    
    assert_eq!(x.a, 5);
}
Run Code Online (Sandbox Code Playgroud)

为什么允许?这是允许的,因为 Rust 允许你修改临时变量,否则很多事情会非常冗长,比如:

fn get_first<T>(vec: Vec<T>) -> Option<T> {
  let first = vec.into_iter().next();
  //                         ^ temporary iterator
  first
}
Run Code Online (Sandbox Code Playgroud)

next()需要迭代器的可变引用。必须将其绑定到可变变量意味着您必须编写:

fn get_first<T>(vec: Vec<T>) -> Option<T> {
  let mut iter = vec.into_iter();
  let first = iter.next();
  first
}
Run Code Online (Sandbox Code Playgroud)

您提供的禁止代码片段不满足编译器的要求,因为您尝试将一个值分配给另一个值,而不是变量:这样做{ var }会创建一个返回变量中的值的块,因此:

fn get_first<T>(vec: Vec<T>) -> Option<T> {
  let mut iter = vec.into_iter();
  let first = iter.next();
  first
}
Run Code Online (Sandbox Code Playgroud)

您可以使用这个临时文件,但不能覆盖它,这是有意为之的,也是一件好事。我认为在 C++ 中,他们称之为左值和右值,块返回右值,并且不能分配给右值。

但是,是的,编译器不会将其视为{ x }.a临时的,这有点愚蠢,没有我能想到的用例,并且可能会造成混乱。