Rust的一些特性

Rust的一些特性

Rust 相对于其他编程语言的一些特性,这里和C++比较

变量与可变性

不同于其他编程语言,Rust的变量默认是不可变的(这句话第一次听很别扭,可以想象成Rust的变量默认是C++的const(不太恰当的类别)),若想要定义可变变量则使用mut关键字

let x = 1;//x不可变
let mut x1 = 1;//x1可变

变量遮蔽

Rust允许定义同名变量,这样会产出变量遮蔽(即之间的变量被新定义的变量遮蔽而不可用)

let x = 1;
let x = 'A';//产生变量遮蔽
//C++中这样的语法是报错的

语句和表达式

Rust是一门基于表达式的语言,所以相较于其他语言,Rust很重视二者的区别:

  1. 语句(Statements)是执行一些操作但不返回值的指令。
  2. 表达式(Expressions)计算并产生一个值。
fn f() -> i32 {
    let x = 520;//语句
    return x;//语句
}
fn f() -> i32 {
    520//表达式
}

上述两个函数均可正常编译通过。

注释

基本注释语法与C++相同,除此之外Rust引入了文档注释(可以生成HTML文档,便于生成和展示项目文档)。

//单行注释

/*
多行注释
*/

///文档注释

所有权

Rust 的核心功能(之一)是 所有权(ownership)。下面是所有权规则:

  1. Rust 中的每一个值都有一个 所有者(owner)。
  2. 值在任一时刻有且只有一个所有者。
  3. 当所有者(变量)离开作用域,这个值将被丢弃。

作用域概念和C++基本一致,所有权的概念就类似C++的RAII机制,从语法层面就实现了对资源的管理。

Rust中变量和数据的交互形式(和C++几乎一致):

  1. 移动(move):堆上的数据(例如String,编译时大小未知)
  2. 克隆(clone):堆上的数据(例如String,编译时大小未知)
  3. 拷贝(copy):只在栈上的数据(例如i32,编译时大小已知)
//例子1  栈上变量发生copy,copy后二者均可用
let x = 5;
let y = x;

//例子2  堆上变量发生move,move后s1所有权转移给s2,s1不可用
let s1 = String::from("hello");
let s2 = s1;

//例子2  堆上变量发生clone,clone后s1依然可用
let s1 = String::from("hello");
let s2 = s1.clone();

Rust的引用与C++几乎一致,特别的存在以下几个规则:

  1. 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用。
  2. 引用必须总是有效的。

Option

Rust没有null类型,其使用Option来解决值为空时的情况.

//Option定义在标准库中
enum Option<T> {
	None,
	Some(T),
}

//简单使用
fn main() {
	let x: i8 = 5;
	let y: Option<i8> = Some(5);
    let z = x + y;//编译会产生错误
}

当有一个 Some 值时,我们就知道存在一个值,而这个值保存在 Some 中。当有个 None 值时,在某种 意义上,它跟空值具有相同的意义:并没有一个有效的值。

Option 为什么就比空值要好呢?

简而言之,因为 Option 和 T(这里 T 可以是任何类型)是不同的类型,编译器不允许像一个肯定有效的值那样使用 Option。换句话说,在对 Option 进行 T 的运算之前必须将其转换为 T。通常这能帮助我们捕获到空值最常见的问题之一:假设某值不为空但实际上为空的情况。从而避免了某变量为空带来的运行时错误,这也是Rust安全的一个体现。

模式和模式匹配

模式是 Rust 中特殊的语法,它用来匹配类型中的结构,无论类型是简单还是复杂。结合使用模式和 match 表达式以及其他结构可以提供更多对程序控制流的支配权。

可能用到模式的地方:

//1.match分支  match必须是穷尽的
match VALUE {
	PATTERN => EXPRESSION,
	PATTERN => EXPRESSION,
	PATTERN => EXPRESSION,
}
//2.if let   主要用于编写等同于只关心一个情况的 match 语句简写
//else是可选的
if let Some(color) = favorite_color {
println!("Using your favorite color, {}, as the background", color);
} else{
println!("Tuesday is green day!");
} 

//3.while let
while let Some(top) = stack.pop() {
	println!("{}", top);
}
//4.for
let v = vec!['a', 'b', 'c'];
for (index, value) in v.iter().enumerate() {
	println!("{} is at index {}", value, index);
}
//5.let
let PATTERN = EXPRESSION;

模式的可反驳性:

模式有两种形式:refutable(可反驳的)和 irrefutable(不可反驳的)。能匹配任何传递的可能值的模式 被称为是 不可反驳的(irrefutable)。一个例子就是 let x = 5; 语句中的 x,因为 x 可以匹配任何值所以 不可能会失败。对某些可能的值进行匹配会失败的模式被称为是 可反驳的(refutable)。一个这样的例子 便是 if let Some(x) = a_value 表达式中的 Some(x);如果变量 a_value 中的值是 None 而不是 Some, 那么 Some(x) 模式不能匹配。

泛型

Rust具有泛型,和C++泛型几乎是类似的

trait

trait 告诉 Rust 编译器某个特定类型拥有可能与其他类型共享的功能。可以通过 trait 以一种抽象的方式 定义共享的行为。类似于其他语言中的接口。

一个类型的行为由其可供调用的方法构成。如果可以对不同类型调用相同的方法的话,这些类型就可以 共享相同的行为了。trait 定义是一种将方法签名组合起来的方法,目的是定义一个实现某些目的所必需 的行为的集合。

//一个简单的例子
//定义一个trait
pub trait Summary {
	fn summarize(&self) -> String;
    //trait默认实现
    fn summarize1(&self) -> String {
		String::from("(Read more...)")
	}
}
//结构体
pub struct NewsArticle {
	pub headline: String,
	pub location: String,
	pub author: String,
	pub content: String,
}
//该结构体实现Summarytrait
impl Summary for NewsArticle {
	fn summarize(&self) -> String {
		format!("{}, by {} ({})", self.headline, self.author, self.location)
	}
}

//使用trait作为参数(类比相当于C++的虚基类。),
//任何实现了Summary trait的类型都是合法参数
pub fn notify(item: &impl Summary) {
	println!("Breaking news! {}", item.summarize());
}

//trait bound语法 (类比相当于c++的concept)
//语法示例1
pub fn notify<T: Summary>(item: &T) {
	println!("Breaking news! {}", item.summarize());
}
//语法示例2,泛型 T 被指定为 item1 和 item2 的参数限制,如此传递给参数 item1 和 item2 值的具体类型必须一致。
pub fn notify<T: Summary>(item1: &T, item2: &T) {}
//还有很多,这里只是抛砖引玉

生命周期

Rust的每一个变量都有其生命周期,基本上和C++类似。特别的是Rust中的生命周期注解语法

**生命周期注解并不改变任何引用的生命周期的长短。**与当函数签名中指定了泛型类型参数后就可以接受 任何类型一样,当指定了泛型生命周期后函数也能接受任何生命周期的引用。生命周期注解描述了多个 引用生命周期相互的关系,而不影响其生命周期。

生命周期注解有着一个不太常见的语法:生命周期参数名称必须以撇号(’)开头,其名称通常全是小写, 类似于泛型其名称非常短。

&i32 // 引用
&'a i32 // 带有显式生命周期的引用
&'a mut i32 // 带有显式生命周期的可变引用

单个的生命周期注解本身没有多少意义,因为生命周期注解告诉 Rust 多个引用的泛型生命周期参数如 何相互联系的。例如如果函数有一个生命周期 ’ a 的 i32 的引用的参数 first 。还有另一个同样是生命周 期 ’ a 的 i32 的引用的参数 second。这两个生命周期注解意味着引用 first 和 second 必须与这泛型生 命周期存在得一样久。

这部分和trait是Rust比较难的部分,这里只是简要概括

闭包

Rust 的 闭包(closures)是可以保存在一个变量中或作为参数传递给其他函数的匿名函数。可以在一个 地方创建闭包,然后在不同的上下文中执行闭包运算。不同于函数,闭包允许捕获被定义时所在作用域中的值。(类比相当于C++中的lambda表达式)

语法比较奇特,集体不详细解释,这应该当成专题学习,这是Rust支持函数式编程的一个重要特性。

个人总结

感觉基础的Rust相较于C++比较不同的地方就是上述内容啦,当然 他还有很多自己高级的语法和特性,有待挖掘中…

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值