首先, rust 成员变量分两类:
- 复制语义: u32, i16 ... , 一般给在栈上分配内存, 新变量赋值时, 会发生值拷贝
- 转移语义: String, 对象. 一般分配在堆上, 有变量赋值时, 没有复制行为, 会转移所有权. 相当于引用传递.
1.结构体 struct
struct 在语义上, 完全依赖其成员属性的语义.
如果成员都是复制语义类型, 那么struct也是复制语义.
此时,为了能实现复制行为,需要加上
#[derive(Copy, Clone)]
#[derive(Debug, Copy, Clone)]
struct A {
a: i32,
b: u32,
}
let a = A { a: 1, b: 2 };
let b = a; // 这里发生复制
println!("{:?}", a); // 这样写没有问题
- 如果成员中包含转移语义, 那么此struct也就是转移语义类型了
#[derive(Debug)]
struct B {
a: i32,
b: String,
}
let a2= B{ a: 3, b: "45".to_string() };
let b2 = a2; // 所以权转移
println!("{:?}", a2); // 这里会出错
- 转移语义 不支持
Copy
#[derive(Debug, Copy, Clone)]
struct B {
a: i32,
b: String, // 转移语义, 不支持Copy --------- this field does not implement `Copy`
}
2.数组
再来看一下数组的用法, 思路 与 struct 一致, 完全依赖成员的语义
let c = ("a".to_string(), "b".to_string());
let d = c;
println!("{:?}", c); // value borrowed here after move : 数组元素包含移动语义,则不支持Copy
let e = (1, 2, 3);
let f = e; // 这里其实发生了Copy, e , f 已经不相干了
println!("{:?}", e);
3. 所有权复制|转移
- 每一个
let
绑定操作,都有一个生命周期- 产生新的作用域的方式, 变量进入下面的范围,都会发生 复制or转移
- 花括号
- match语法
- for i in v 语法
- if let
- while let
- 函数
- 闭包
4.引用 借用
& 为引用, &mut 为可变引用, 也称为可变借用.
从借用生命周期出来后, 返还变量使用权.
借用三个原则:
- 借用方 生全周期不能长于 借出方 // 防止出现 悬垂指针
- 可变借用, 不可以再有别名. // 不可以再次 let mut = ?
- 不可变借用, 不能再次出借为 可变借用
5.生命周期
来个例子:
let r;
{
let x = 5;
r = &x; // ^^ borrowed value does not live long enough
}
println!("r : {}", r);
x 的生命周期不够长, 导致了在花括号结束时, x 已经失效
5.1 显式生命周期参数
&i32; 引用
&'a i32; 有生命周期的引用
&'a mut i32; 有生命周期的可变引用
定义一个函数: 对于返回参数带生命周期的函数, 入参也要带 生命周期参数
fn foo<'a>(s: &'a str, t: &'a str) -> &'a str { }
来个具体例子:
fn main() {
let a = String::from("hello");
let b = &a;
{
let c = String::from("rust");
let rst = long_str(b, &c); // 变量c的生命周期, 被提升到b同等级?
println!("longer : {}", rst);
}
}
fn long_str<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() > b.len() { a } else { b }
}
结果: longer : hello
网友评论