文章目录 一、所有权转移 二、Owner + Move 的语义也会带来一些复杂度。 三、生命周期 生命周期标注 单引用---无需标注生命周期 包含引
文章目录
- 一、所有权转移
- 二、Owner + Move 的语义也会带来一些复杂度。
- 三、生命周期
- 生命周期标注
- 单引用---无需标注生命周期
- 包含引用类型成员的结构体
一、所有权转移
一般情形下的函数调用移动所有权。
// takes_ownership 取得调用函数传入参数的所有权,所以变量进来了就出不去了fn takes_ownership(some_string: String) {
println!("{}", some_string);
} // 这里,some_string 移出作用域并调用 `drop` 方法。占用的内存被释放
// gives_ownership 将返回值移动给调用它的函数
fn gives_ownership() -> String {
let some_string = String::from("hello");
some_string // 返回 some_string 并移出给调用的函数
}
// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(mut a_string: String) -> String {
a_string.push_str(", world");
a_string // 返回 a_string 将所有权移出给调用的函数
}
fn main()
{
let s1 = gives_ownership();
takes_ownership(s1); // 所有权转给了 takes_ownership 函数
// println!("s1= {}", s1); // s1 不可用了
let s2 = String::from("hello");
let s3 = takes_and_gives_back(s2); // s2 被移动到 takes_and_gives_back 中
//println!("s2={}", s2); //s2 不可用了
println!("s3={}", s3);
}
二、Owner + Move 的语义也会带来一些复杂度。
#[derive(Debug)] // 使用 `{:?}`的方式输出结构体struct Person {
name :String,
email:String,
}
let _name = p.name; // 把结构体 Person::name Move掉
println!("{} {}", _name, p.email); //其它成员可以正常访问
// println!("{:?}", p); //编译出错 "value borrowed here after partial move"
p.name = "Hao Chen".to_string(); // Person::name又有了。
println!("{:?}", p); //可以正常的编译了
三、生命周期
Rust为了解决“野引用”的问题,在有多个变量引用到一个对象上,还不能使用额外的引用计数来增加程序运行的复杂度。那么,Rust就要管理程序中引用的生命周期了,而且还是要在编译期管理,如果发现有引用的生命周期有问题的,就要报错。
fn order_string(s1 : &str, s2 : &str) -> (&str, &str) {if s1.len() < s2.len() {
return (s1, s2);
}
return (s2, s1);
}
let str1 = String::from("long long long long string");
let str2 = "short string";
let (long_str, short_str) = order_string(str1.as_str(), str2);
println!(" long={} nshort={} ", long_str, short_str);
我们有两个字符串,str1 和 str2 我们想通过函数 order_string() 对其排序,你会发现,这段代码编译不过。编译器会告诉你,order_string() 返回的 引用类型 &str 需要一个 lifetime的参数 – “ expected lifetime parameter”。这是因为Rust编译无法通过观察静态代码分析返回的两个引用返回值,到底是(s1, s2) 还是 (s2, s1) ,因为这是运行时决定的。所以,返回值的两个参数的引用没法确定其生命周期到底是跟 s1 还是跟 s2,这个时候,编译器就不知道了。
生命周期标注
fn long_string<'a>(s1 : &'a str, s2 : &'a str) -> (&'a str, &'a str) {if s1.len() > s2.len() {
return (s1, s2);
}
return (s2, s1);
}
单引用—无需标注生命周期
函数 foo() 的参数和返回值都是一个引用,他们的生命周期是一样的,编程器可以自己推导出来,也就可以编译通过。
fn foo (s: &mut String) -> &String {s.push_str("coolshell");
s
}
let mut s = "hello, ".to_string();
println!("{}", foo(&mut s))
包含引用类型成员的结构体
#[derive(Debug)]struct User<'a>{
username: &'a str,
email:String,
age:u8,
}
fn main() {
let word = String::from("zhang_san");
let email_ = String::from("zhang_san@qq.com");
let stu = User{username:&word,email:email_,age:12};
println!("{:?}",stu);
}
构造函数,我都不知道该如何构造了,在P235 中建造者模式中并没有引用,本来想参考来着
#[derive(Debug)]struct User<'a>{
username: &'a str,
email:String,
age:u8,
score:&'a i8,
}
impl <'a> User<'a> {
// fn new() ->User<'a>{
// //
// }
fn set_username(&mut self, s : &'a str) {
self.username = s;
}
fn set_score(&mut self, i : &'a i8) {
self.score = i;
}
}
fn main() {
let word0 = String::from("zhang_san");
let word1 = String::from("li_si");
let email_ = String::from("zhang_san@qq.com");
let score_0 = 90;
let score_1 = 90;
let mut stu = User{username:&word0,email:email_,age:12,score:&score_0};
println!("{:?}",&stu); //User { username: "zhang_san", email: "zhang_san@qq.com", age: 12, score: 90 }
let stu2 = &stu.set_username(&word1);
println!("{:?}",stu2); // ()
let stu3 = &stu.set_score(&score_1);
println!("{:?}",stu3); // ()
}