rust生命周期+所有权+借用检查,直面内存安全问题
把值压到stack上不叫分配,因为位置永远在stack的顶端,
挨着放就行。
fn main() { let s = String::from("hello world"); take_ownership(s);//s被移动到函数里面,从这以后s不再有效,所以下面打印就会报错 // println!("{}", s);//报错 let x = 6; makes_copy(x);//x是i32类型,i32实现了Copy Trait,所以往函数里面传的是x的副本 println!("{}", x);//x只是copy,所以这里还能打印 } fn makes_copy(num: i32) { println!("{}", num); } fn take_ownership(str: String) { println!("{}", str); }
fn main() { let s1 = String::from("hello world"); //引用s1但并不拥有s1,因为这个&s1并不拥有s1,所以当它走出作用域的时候,它指向的值并不会被清理掉 let len = calculate_length(&s1); println!("the length of {} is: {}", s1, len); } fn calculate_length(s: &String) -> usize { s.len() }//走到这s就出了作用域,但是由于它并不具有它所指向字符串的所有权,所以它所指向的值不会被清理掉, //跟其他参数一样,s的作用域还是那么大,但与其他参数不同的是,它不会在离开自己作用域的时候销毁其指向的数据 //因为它并不拥有该数据的所有权。 //所以当一个函数使用引用作为参数而不是真实的值作为参数的时候,我们就不必为了归还所有权,而把这个值 返回回去, //因为在这种情况下,我们就根本没有获得所有权,而这种以引用作为函数参数的行为,我们就把它称为借用,s在第八行结束后就已经除了作用域,就会被销毁了,而对s的引用却返回了,所以这个引用指向一个已被释放的内存地址,这就是悬空指针。
rust在编译的时候就会报错,防止这种悬空指针。
上图的意思,比如汉字在UTF8编码中占3个字节
fn main() { let s = String::from("hello world"); let word_index = first_word(&s); // s.clear(); println!("s={} index={}", s, word_index); } fn first_word(s: &String) -> usize { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return i; } } s.len() }
fn main() { let mut s = String::from("hello world"); let word_index = first_word(&s); s.clear(); println!("s={} index={}", s, word_index); } fn first_word(s: &String) -> usize { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return i; } } s.len() }
fn main() { let mut s = String::from("hello world"); let word_index = first_word(&s); s.clear(); println!("s={} index={}", s, word_index); } fn first_word(s: &String) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return &s[..i]; } } &s[..] }
上面就会报错
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable --> src/main.rs:4:5 | 3 | let word_index = first_word(&s); | -- immutable borrow occurs here 4 | s.clear(); | ^^^^^^^^^ mutable borrow occurs here 5 | println!("s={} index={}", s, word_index); | ---------- immutable borrow later used here
那为什么之前的(代码如下)不报错呢?
fn first_word(s: &String) -> usize { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return i; } } s.len() }
因为这个s的不可变引用在first_word函数结束的时候已经失效,
但是上面报错的是返回了切片,切片是对s的一部分引用,返回后,就和s.clear()这个可变引用在同一个作用域了
从上图可以看出s.clrear() 其实等价于clear($mut s)
fn main() { let s = String::from("hello world"); let word = first_word(&s[..]); println!("s={} index={}", s, word); let s2="hello world"; let word2 = first_word(s2); println!("s={} index={}", s2, word2); } fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return &s[..i]; } } &s[..] }