rust_interview icon indicating copy to clipboard operation
rust_interview copied to clipboard

[Practice] 介绍id函数及其在代码中的技巧

Open ZhangHanDong opened this issue 8 years ago • 9 comments
trafficstars


#![allow(dead_code)]

fn main() {
    fn id<T>(x: T) -> T { x }
 
    struct List {
        next: Option<Box<List>>,
    }
    
    impl List {
        fn walk_the_list(&mut self) {
            let mut current = self;
            loop {
                match id(current).next {
                    None => return,
                    Some(ref mut inner) => current = inner,
                }
            }
        }
    }
}

如果不使用id函数,使用别的方法,该如何修正错误?

考察点: 所有权机制

ZhangHanDong avatar Nov 04 '17 03:11 ZhangHanDong

&mut 没有实现 Copy, id 把 current move 了, 这样编译器就不会认为在下一次 loop 中 current 还被 borrow, 同理赋值也是可以的

事实上这题比较绕, 如果给 id 加上 type annotation, 就会失效, 实属奇技淫巧

#![allow(dead_code)]

fn main() {
    struct List {
        next: Option<Box<List>>,
    }

    impl List {
        fn walk_the_list(&mut self) {
            fn walk(current: &mut List) {
                match current.next {
                    None => (),
                    Some(ref mut inner) => walk(inner),
                }
            }
            walk(self)
        }
    }
}

iovxw avatar Nov 24 '17 17:11 iovxw

@iovxw 确实比较绕,哈哈。但目的主要是考察下对所有权的理解。 欢迎出题,先放到issues里,最后再选择归类。

ZhangHanDong avatar Nov 25 '17 02:11 ZhangHanDong

嘿 !

#![allow(dead_code)]

fn main() {
    struct List {
        next: Option<Box<List>>,
    }

    impl List {
        fn walk_the_list(&mut self) {
            let mut current = self;
            loop {
                let current2 = current;
                match current2.next {
                    None => return,
                    Some(ref mut inner) => current = inner,
                }
            }
        }
    }
}

biluohc avatar Nov 25 '17 04:11 biluohc

@iovxw 利用递归参数引用的方式来绕过借用检查! 这个思路好!

huangjj27 avatar Nov 25 '17 07:11 huangjj27

我还有一点问题, 现在的所有权检查是根据词法作用域来判断的吧? 所以如果在match中使用了非Copy的变量, 则会move, 引起后面的current重新绑定时, 借用检查错误, 那么之后的NLL实现后, 是否能够允许如下代码的写法呢?

#![allow(dead_code)]

fn main() { 
    struct List {
        next: Option<Box<List>>,
    }
    
    impl List {
        fn walk_the_list(&mut self) {
            let mut current = self;
            loop {
                match current.next {  // 不需要特别的处理, 仅仅使用current即可匹配
                    None => return,
                    Some(ref mut inner) => current = inner,
                }
            }
        }
    }
}

huangjj27 avatar Nov 25 '17 07:11 huangjj27

@huangjj27 现在说还比较早,等NLL能用了再说吧

ZhangHanDong avatar Nov 25 '17 07:11 ZhangHanDong

@ZhangHanDong 实证NLL可以通过编译. https://play.rust-lang.org/?gist=ef67d8953228455fb692400650dc4a51&version=nightly

huangjj27 avatar Feb 06 '18 16:02 huangjj27

看起来NLL这个写法很自然啊

mzji avatar Aug 03 '18 11:08 mzji

nll stable 了,可以 close 了

iovxw avatar Dec 27 '18 11:12 iovxw