理解绑定和借用

时间:2016-05-25 07:27:10

标签: rust

我有以下简单程序

fn main() {
    let a = 10;
    let b: i32;
    let r: &i32;

    b = a;      // move?
    r = &a;     // borrow?

    println!("{}", a);
    println!("{}", b);
    println!("{}", r);
    println!("{}", &r);
    println!("{}", *r);
}

输出

10
10
10
10
10
  1. 即使移动了值,第一次打印也不会失败。这是因为原始类型还是我错过了什么?
  2. 第二次打印似乎没问题。
  3. 第三个直接打印参考 - 不应该得到内存地址,因为这是一个参考?
  4. 第四个打印是对引用的引用,我认为应该打印一个内存地址?
  5. 第五个印刷品似乎是合理的,因为(我认为)*是取消引用该引用的value at运算符。
  6. 似乎我并没有完全了解整个事情。

    请详细解释 正在进行的事情。

    相关: Move vs Copy in Rust

3 个答案:

答案 0 :(得分:2)

关于 1 :是的,因为它是一个原始变量,更具体地说是一个实现Copy特征的类型。所有这些Copy - 类型都使用复制语义而不是移动语义。

关于 3 println!自动取消引用它的参数 - 这是用户在99%的情况下想要的内容。

关于 4 :再次,自动取消引用参数......直到它成为非引用类型。

答案 1 :(得分:2)

1,2 =>您正在使用i32Copy,因此在实践中b = a.clone()

3,4,5 =>您与Deref trait混淆了。我发现更容易推理所有权/借款而不是生锈的参考。 r = &a表示 r借用a,以便我可以在以后访问其值,其他人将拥有它并负责删除它

答案 2 :(得分:1)

其他答案大多是正确的,但有一些小错误。

1。 i32实现Copy,因此当您将其分配给第二个变量绑定时,第一个绑定不需要失效。任何实现Copy的类型都将具有此属性。

3。您已要求使用与Display trait对应的{}格式化值。此特征有an implementation,用于引用实现Display的类型:

impl<'a, T> Display for &'a T where T: Display + ?Sized {
    fn fmt(&self, f: &mut Formatter) -> Result { Display::fmt(&**self, f) }
}

这只是委托引用类型的实现。

4。与#3相同 - 对实现Display的类型的引用的引用将只委派两次。 Deref没有发挥作用。

这是其他人没有提及的偷偷摸摸的事情。 println!,这意味着它比常规函数调用具有更多功能。它所做的一件事是自动将引用引用到任何参数。这就是允许您在不失去所有权的情况下打印出未实现Copy的值的原因。

使用此代码:

let a = 10;
println!("{}", a);

扩展版实际上是这样的(略微清理):

let a = 10;

static __STATIC_FMTSTR: &'static [&'static str] = &["", "\n"];

::std::io::_print(::std::fmt::Arguments::new_v1(__STATIC_FMTSTR, &match (&a,) {
    (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)],
}));

因此,传递给println!所有都是一个参考。如果引用打印出内存地址,那将不会非常有用。

除了有用之外,Rust更多地关注值语义而不是引用语义。当您有值移动和频繁更改地址时,值的位置不是非常一致或有用。

另见