Rust设计之形

本文探讨Rust编程语言的设计核心,包括所有权概念,如何通过所有权和借用解决内存安全问题,详细阐述只读借用(&)、可变借用(&mut)以及借用规则。此外,还介绍了生命周期的概念,如何防止悬垂指针,以及泛型和Trait在Rust中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Rust设计之形

参考视频:https://www.bilibili.com/video/BV1564y1177A

Rust要解决的问题

先看以下C语言的代码:

typedef struct Dummy { int a; int b; } Dummy;

void foo(void)
{
	Dummy *ptr = (Dummy *)malloc(sizeof(struct Dummy));
	Dummy *alias = ptr;
	free(ptr);
	int a = alias.a; // Use afoter free
	free(alias); // Double free
}
  • 可以看到变量alias使用了已经被释放的内存,结果是不可控的
Rust解决方案:所有权+借用
fn main() {
	let x = String::from("hello");
	let y = x;
	// err[E0382]: use of moved value: `x`
	drop(x);
}
  • Rust将堆上的数据视为资源,每个资源都只能有唯一的所有者
  • 能够从资源的所有者处借用资源
  • 当资源被其他代码借用时,资源的所有者不可以释放资源或修改资源
  • 编译时检查,无运行时开销
借用规则
  • 借用可以分为可变借用、只读(共享)借用
  • 不允许对不可变资源进行可变借用
  • 允许同时存在多个对同一对象的只读借用,但是可变借用拥有对被借用对象的独占权
  • 借用的生命周期需要小于被借用资源的生命周期
只读借用(&)
struct Dummy { a: i32, b: i32 }

fn foo() {
	let mut res = Box::new(Dummy{
		a: 0,
		b: 0
	});

	take(&res);
	res.a = 2048;
}

// res 资源被arg只读借用
fn take(arg: &Box<Dummy>) {
	arg.a = 2048; // 编译错误:Cannot mutate via an immutable reference
} // 资源仍然被res持有,take返回时不会释放
可变借用(&mut)
struct Dummy { a: i32, b: i32 }

fn foo() {
	let mut res = Box::new(Dummy{
		a: 0,
		b: 0
	});

	take(&mut res);
	res.a = 4096;

	let borrower = &mut res;
	let alias = &mut res; // 不允许存在多个对同一资源的可变借用
}

fn take(arg: &mut Box<Dummy>) {
	arg.a = 2048;
}
可变性
  • 类似函数式语言,Rust中所有的资源都默认不可变
  • 需要使用mut关键字声明某个资源为可变的
struct Dummy { a: i32, b: i32 }

fn foo() {
	let res = Box::new(Dummy{
		a: 0,
		b: 0
	});
	
	res.a = 2048; // 错误:资源时不可变的
}

生命周期

  • 编译器使用生命周期对代码逻辑进行限制:借用的存活时间不应该比被借用对象长。只要这一规则能够贯彻,那么程序将不可能存在悬垂指针问题
  • 生命周期可以理解为变量作用域的长度,变量a比变量b“活得长”即a的作用域能够覆盖b的作用域
let x = 0;
let y = &x;
let z = &y;

=》自动类型推导,自动声明周期推导,解开语法糖

'a: {
	let x: i32 = 0;
	'b: {
		let y: &'b i32 = &'b x;
		'c: {
			let z: &'c &'b i32 = &'c y;
		}
	}
}
拒绝悬垂指针
fn as_str(data: &u32) -> &str {
	let s = format!("{}", data);
	&s
}

fn main() {
	let x: u32 = 0;
	println!("{}", as_str(&x));
}

推导:

fn as_str<'a>(data: &'a u32) -> &'a str {
	'b {
		let s = format!("{}", data);
		return &'b s
	}
}

fn main() {
	'c: {
		let x: u32 = 0;
		'd: {
			// 生成一个新生命周期 ’d,因为对 x 的借用并不需要
			// 在整个 ‘c 生命周期中均有效。as_str所返回的引用的生命周期需要与 ’d 相同,然而这显然是不可能的
			println!("{}", as_str<'d>(&'d x));
		}
	}
}

泛型与Trait

  • Rust使用Trait对类型的行为进行抽象
  • 组合优于继承

Trait的作用:

  • 接口抽象
  • 泛型参数约束
  • 类型标签(Copy、Clone)
  • 抽象类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值