关于借用的一个小问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dangoron
V2EX    Rust

关于借用的一个小问题

  •  
  •   dangoron 2019-01-14 19:18:31 +08:00 5239 次点击
    这是一个创建于 2518 天前的主题,其中的信息可能已经有所发展或是发生改变。

    刚看完 rust 官方教程,感觉非常新鲜,上手就写了一个 two sum 的题( leetcode 居然支持 rust 了)。 写的过程中发现一个不解之处,在对Vector和列表中的元素进行引用的时候一般会写let x = &vec[0];,不过如果直接写let x = vec[0]同样是可以使用的,只是x的类型不同,如果vec里的元素都是i32的话,不加&的写法输出的x会是i32类型。而且,在let x = vec[0]之后,vec[0]仍然可以访问,也就是说并没有失去所有权,于是怀疑这里做了克隆。继续进行测试:

    #[derive(Debug)] struct Val { val: i32, } fn main() { let vec = vec![Val{ val: 0 }, Val{ val: 1 }, Val{ val: 2 }]; let x = vec[0]; println!("x: {:?}", x); } 

    let x = vec[0]处会提示cannot move out of borrowed content错误,反而let x = &vec[0]是可行的,给Val结构添加#[derive(Clone)]标注依然会有错误,所以好像这也并不是在做克隆。rust book 上没有关于这两者区别的讨论,只是写了借用的做法。希望有人可以指教一下这两者的区别~

    7 条回复    2019-01-15 16:58:25 +08:00
    quinoa42
        1
    quinoa42  
       2019-01-15 10:35:25 +08:00   1
    let x = vec[0]; 是 move,move 之后 ownership 交给了 x
    rust 里 trait 分 Copy 和 Clone,这俩的区别就是 Copy 默认不需要很耗时的调用而 Clone 默认需要,所以 Copy 会自动调用而 Clone 不会(而 scalar,比如 i32,都实现了 Copy )

    换个角度:
    ```rust
    #[derive(Debug, Clone, Copy)]
    struct Val {
    val: i32,
    }

    fn main() {
    let vec = vec![Val{ val: 0 }, Val{ val: 1 }, Val{ val: 2 }];
    let x = vec[0];
    println!("x: {:?}", x);
    }
    ```
    这样就不会报错,因为 let x = vec[0]自动调用了 Copy::clone()

    更进一步的理解首先需要参考 Index::index():
    https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-Index%3CI%3E
    但是仔细看会发现,index()返回的是个 reference …………不能直接 let x = vec[0]的原因是,
    如果用了[]这个语法糖,rust 会在调用 index()之后再调用一次 deref
    所以直接调用 index()也能编译:
    ```rust
    use std::ops::Index;
    #[derive(Debug)]
    struct Val {
    val: i32,
    }

    fn main() {
    let vec = vec![Val{ val: 0 }, Val{ val: 1 }, Val{ val: 2 }];
    let x = vec.index(0);
    println!("x: {:?}", x);
    }
    ```
    quinoa42
        2
    quinoa42  
       2019-01-15 10:39:10 +08:00
    忘了说了,所以楼主的代码不能编译通过的原因是 vec.index(0)是个 reference,reference 不能转移 ownership
    而后一个版本(直接调用 index())的时候,x 的类型是&Val,这里是个 borrow,所以编译可以通过
    dangoron
        3
    dangoron  
    OP
       2019-01-15 15:05:44 +08:00
    @quinoa42 谢谢你的释疑。感觉 rust 的所有权问题还是很复杂的,尤其是看到链表的实现之后。。
    dangoron
        4
    dangoron  
    OP
       2019-01-15 16:04:25 +08:00
    @quinoa42 还有个可能很小白的问题。。as_ref 和 as_mut 和普通的 & 和 &mut 的主要区别在哪里呢
    quino42
        5
    quinoa42  
       2019-01-15 16:35:56 +08:00
    @dangoron
    比方说 as_mut 的 type 是 fn as_ref(&self) -> &T,也就是说 as_mut 和 as_ref 的返回的 reference 包含的类型不一定要和 self 的类型一致
    书里唯一一次提到 as_ref ( https://doc.rust-lang.org/1.30.0/book/2018-edition/ch17-03-oo-design-patterns.html?highlight=as_ref#adding-the--approve--method-that-changes-the-behavior-of--content )是 Option::as_ref,效果是从 Option<T>变成 Option<&T>,但其实 Option 貌似没实现 AsRef trait...(毕竟和要求的 signature 不一样)
    https://doc.rust-lang.org/std/option/enum.Option.html#method.as_ref
    但 Arc::as_ref 可以作为一个典型例子:
    https://doc.rust-lang.org/src/alloc/sync.rs.html#1946-1948
    quinoa42
        6
    quinoa42  
       2019-01-15 16:36:43 +08:00
    比方说 as_mut -> 比方说 as_ref
    dangoron
        7
    dangoron  
    OP
       2019-01-15 16:58:25 +08:00
    @quinoa42 多谢!也就是说,在类型不需要变化的时候用 & 和 &mut 就够了,需要变化的时候可以用 as_ref 或者 as_mut。涉及到指针还真是头疼 0.0
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     891 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 22ms UTC 19:47 PVG 03:47 LAX 11:47 JFK 14:47
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86