当前位置 : 主页 > 编程语言 > java >

Rust (三)Owner语义与生命周期

来源:互联网 收集:自由互联 发布时间:2022-07-17
文章目录 ​​一、所有权转移​​ ​​二、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); // ()
}


网友评论