Rust---入门

目录

0 概述

1 环境搭建

2 简单认识Rust

3 Rust语言

3.1 基本构成

3.2 语句与表达式

3.3 变量

3.4 函数

3.5 流程控制

3.6 基本数据类型

扫描二维码关注公众号,回复: 9067108 查看本文章

3.7 复合数据类型

3.8 注释与打印


0 概述

Rust是一门同时追求安全、并发和性能系统级编程语言,有直接操作底层硬件的能力,同时拥有高级的抽象表达能力。

  • Rust语言注重安全。它建立了严格的安全内存管理模型:1.所有权系统;2.借用和生命周期
  • Rust语言追求高效开发和性能。它的抽象是零成本的,并不会存在运行时性能开销,这一切都是在编译期完成的。要做到零成本抽象,Rust需要泛型trait
  • Rust语言具有实用性。它已经为开发工业级产品做足准备;为了开发者更方便地相互协作,它提供了包管理器Cargo;为了方便开发者学习,它在不断地完善官方文档,不断改进Rust,提升Rust的友好度。
  • Rust本身就是一个开源项目。
  • Rust应用在多个领域中,如数据库、游戏、云计算、安全、区块链等。

1 环境搭建

请参考这里的链接---->>>>>时光隧道

2 简单认识Rust

参考官方的入门教程,简单了解Rust。

3 Rust语言

3.1 基本构成

  • 语言规范

《参考手册》是官方团队维护的一份参考文档,虽然并非正式的语言规范,但它比“圣经”更加详尽全面。

RFC文档,适合初学者深入了解某个语言特性的来龙去脉。

  •  编译器rustc

rustc可以运行在多个平台上(windows、Mac、linux),支持交叉编译,支持多目标平台。

  • 核心库 

核心库不依赖于操作系统和网络等相关的库,不提供并发和IO。可以通过在模块顶部引入#![no_std]来使用核心库。做嵌入式开发时,核心库是必需的。

  • 标准库 

标准库提供应用程序开发所需要的基础和跨平台支持。如并发、IO和运行时,还有与OS交互的基础功能,错误处理以及各种迭代器。

  • 包管理器 Cargo

 Cargo类似于Python中的pip、Node.js中的npm,它还能够管理整个工作流程,从创建项目、运行单元测试和基准测试,到构建发布链接库,再到运行可执行文件。

3.2 语句与表达式

Rust语法中可以分成两大类:语句和表达式。

  • 语句有可分为两种:(1)声明语句,用于声明变量、常量、结构体等;(2)表达式语句,特指以分号结尾的表达式。
  • 表达式,主要用于计算求值。

如下面的例子:

fn main() {
	let a = 3;
	let b = 4;
    println!("sum_one() = {}",sum_one(a,b));
	println!("sum_two() = {}",sum_two(a,b));
	println!("sum_three() = {:?}",sum_three(a,b));
}

fn sum_one(a:i32,b:i32)->i32{
	//这是表达式,sum函数直接返回表达式求得的值
	a + b
}

fn sum_two(a:i32,b:i32)->i32{
	//这是表达式语句
	let c = a + b;
	//这是表达式,返回c的值
	c
}

fn sum_three(a:i32,b:i32)->(){
	//这是表达式语句,分号后面什么都没有时,返回单元值()
	a + b;
}

 运行结果:

Rust中的表达式分为位置表达式和值表达式。

  • 位置表达式,表示内存位置。
  • 值表达式,一般只引用了某个存储单元地址中的数据。

3.3 变量

变量的创建

fn main() {
    //关键字let用于创建变量
	//创建变量a,默认为不可变
	let a = 3;
	//给变量a重新赋值,会产生编译时错误
	a = 4;
	println!("a = {}",a);
}

错误信息如下:

如果想为变量二次赋值,修改如下:

fn main() {
	//关键字mut,用于声明变量为可变的
	let mut a = 3;
	println!("a = {}",a);
	a = 4;
	println!("a = {}",a);
}

3.4 函数

定义

//关键字fn,用于定义函数
fn main() {//程序的入口
	let a = sum(1,2);
	println!("a = {}",a);
}
//参数:(a:i32,b:i32),i32为参数的数据类型
//返回值:-> i32,i32为返回值的数据类型
fn sum(a:i32 ,b:i32) -> i32{
	//不使用关键字return
	a + b
}

作用域

fn main(){
	let v = "hello world!";
	assert_eq!(v,"hello world!");//使用断言验证字符串
	let v = "hello Rust!";//以上两个变量v的作用域为main函数内
	//这种连续用let定义同名变量的做法叫做“变量遮蔽”
	assert_eq!(v,"hello Rust!");
	{
		let v = "hello world!";//这个变量v的作用域为当前大括号内
		assert_eq!(v,"hello world!");
	}
	assert_eq!(v,"hello Rust!");
	//这证明在词法作用域内使用花括号开辟新的词法作用域后,两个作用域是互相独立的
}

3.5 流程控制

条件表达式

fn main(){
	let n =5;
	let big_n = if n < 10 && n > -10{
		n * 10
	}else{
		"hello"
	};
	//if和else返回的类型不同,编译时会报错
	println!("big_n = {}",big_n);
}

 

循环表达式

fn main(){
	//for...in循环表达式
	for n in 1..101{//实质是一个迭代器,n的取值范围为1到100
		if n % 15 == 0{
			println!("fizzbuzz");
		}else if n % 3 == 0{
			println!("fizz");
		}else if n % 5 == 0{
			println!("buzz");
		}else{
			println!("{}",n);
		}
	}
}
fn main(){
	//while true
	let y = while_true(5);
	assert_eq!(y,6);
}

fn while_true(x:i32) -> i32 {
	//编译时会报错,由于返回期望返回的值类型为i32
	//但编译时编译器会忽略循环体内的表达式
	//所以编译器认为返回值为单元值()
	while true{
		return x + 1;
	}
	//可以这样修改
	//x
	//程序不会运行到这里,只是告诉编译器函数返回的是i32类型的数据
}
//编译器建议使用loop代替while true
fn main(){
	let mut n = 10;
	loop{
		n = n - 1;
		if n < 0{
			break;
		}
		println!("n = {}",n);
	}
}

 match表达式与模式匹配

fn main(){
	let number = 8;
	//match模式匹配,类似于其他语言中的switch...case
	match number{
	//match分支(左边 => 右边),左边就是模式,右边就是执行代码
	//与if表达式类似,所有分支都必须返回同一个类型
		0 => println!("Origin"),//单值匹配
		1...3 => println!("All"),//范围匹配
		|5|7|13 => println!("Bad Luck"),//多值匹配
		n @ 42 => println!("Answer is {}",n),//将42绑定到变量n,供执行语句使用
		_ => println!("Common"),//类似于default,处理剩余情况
	}
}

if let 和 whlie let 表达式

fn main(){
	let boolean = true;
	let mut binary = 0;
	//与match类似,if let表达式等号左边为模式,右边为要匹配的值
	if let true = boolean{//如果boolean为true,将binary修改为1
		binary = 1;
	}
	println!("binary = {}",binary);
}
fn main(){
	let mut v = vec![1,2,3,4,5];//动态数组
	while let Some(x) = v.pop() {
	//Some()用于匹配数组中的元素,v.pop()返回的Option类型会自动绑定到变量x
		println!("{}",x);
	}
	//当数组的值取空时,自动跳出循环
}

3.6 基本数据类型

fn main(){
	//布尔类型
	let x = true;//等价于下面的y声明语句,Rust会自动推断其类型为bool
	let y : bool = false;//:bool用于显式声明数据类型
	
	//基本数字类型
	//固定大小的类型
	//无符号整数
	//u8,大小1个字节,范围0 ~ 2^(8-1)
	//u16,大小2个字节,范围0 ~ 2^(16-1)
	//u32,大小4个字节,范围0 ~ 2^(32-1)
	//u64,大小8个字节,范围0 ~ 2^(64-1)
	//u128,大小16个字节,范围0 ~ 2^(128-1)
	//有符号整数
	//i8,大小1个字节,范围-2^7 ~ 2^(7-1)
	//i16,大小2个字节,范围-2^15 ~ 2^(15-1)
	//i32,大小4个字节,范围-2^31 ~ 2^(31-1)
	//i64,大小8个字节,范围-2^63 ~ 2^(63-1)
	//128,大小16个字节,范围-2^127 ~ 2^(127-1)
	let num = 42u32;//类型后缀,代表这是一个u32类型,无符号32位整数类型
	let num : u32 = 42;//与上面的声明效果相同
	let num = 42;//不加后缀或指定数据类型,Rust默认推断为i32类型
	let num = 0x2A;//前缀0x表示十六进制
	let num = 0o106;//前缀0o表示八进制
	let num = 0b1101_1011;//前缀0b表示二进制
	assert_eq!(b'*',42u8);//字节字面量,等价于42u8
	//动态大小类型
	//usize,大小4个或8个字节,范围0~2^(32-1)或0~2^(64-1),取决于机器字长
	//isize,大小4个或8个字节,范围-2^31~2^(31-1)或-2^63~2^(63-1),取决于机器字长
	//浮点数类型
	//f32,大小4个字节,至少6位有效数字,范围-3.4*10^38~3.4*10^38
	//f64,大小8个字节,至少15位有效数字,范围-1.8*10^308~1.8*10^308
	let num = 3.1415926f64;//声明64位浮点数
	println!("{:?}",std::f32::INFINITY);//无穷大
	println!("{:?}",std::f32::NEG_INFINITY);//负无穷大
	println!("{:?}",std::f32::NAN);//非数字值
	println!("{:?}",std::f32::MIN);//最小值
	println!("{:?}",std::f32::MAX);//最大值
	
	//字符类型
	//使用单引号定义字符类型,大小4个字节
	let ch = 'r';
	println!("size_of_val(ch) = {}",std::mem::size_of_val(&ch));//打印ch的大小,单位字节
}

数组类型

fn main(){
	//定义数据类型为u32,固定长度为5,名叫arr的不可变绑定数组
	let arr:[u32;5] = [1,2,3,4,5];
	//即使定义为let mut数组,也只能修改已存在索引位上的元素
	//let mut arr:[u32;5] = [1,2,3,4,5];
	//arr[5] = 6;//编译时报错
	//arr[2] = 30;
	
	//创建初始值为0且指定长度为5的数组
	//let arr = [0;5];
	
	//范围类型包括左闭右开和全闭两种区间
	
	//左闭右开区间示例,0..5表示左闭右开区间,即0~4
	for index in 0..5{
		println!("{}",arr[index]);
	}
	println!("\r\n------------------------\r\n");
	//全闭区间示例,1..=3表示全闭区间,即1~3
	for index in 1..=3{
		println!("{}",arr[index]);
	}
	
	//越界访问时,编译器会报错
	//println!("{}",arr[5]);
}

切片类型

fn main(){
	let arr:[i32;5] = [1,2,3,4,5];
	
	//使用&操作对数组进行引用
	let a = &arr;
	println!("{:?}",a);
	println!("{}",a[1]);
	
	println!("--------------------------");
	
	//也可以结合范围对数组进行切割
	let a = &arr[1..];//获取arr数组中索引位置1之后的所有元素
	println!("{:?}",a);//打印切片
	println!("{}",a[0]);//打印切片中索引位置0的元素
	
	println!("--------------------------");
	
	println!("{}",a.len());//获取切片长度
	println!("{}",a.is_empty());//判断数组是否为空
	
	println!("--------------------------");
	
	//定义可变绑定数组
	let mut arr_1:[i32;5] = [1,2,3,4,5];
	//定义可变切片
	let a_1 = &mut arr_1[1..=2];
	println!("{:?}",a_1);
	//可以通过索引位置修改切片
	a_1[0] = 20;
	println!("{:?}",a_1);
}

str字符串类型

Rust将字符串分成两类:

  1. 固定长度的字符串,不可随便更改其长度,即str字符串
  2. 可增长字符串,可以随意改变其长度,即String字符串
fn main(){
	let s:&'static str = "Hello World!";//静态生命周期字符串
	
	let ptr = s.as_ptr();//字符串指针
	let len = s.len();//字符串长度
	
	println!("len = {}",len);
	
	let s_1 = unsafe{
		//通过传入指针和长度,将相应的字节序列转换为切片类型&[u8]
		let slice = std::slice::from_raw_parts(ptr,len);
		//将得到的切片类型转换为str字符串
		std::str::from_utf8(slice)
	};//因为整个过程都没有验证字节序列是否为合法的UTF8字符串,所以放在unsafe块内
	
	println!("s_1 = {:?}",s_1);
}

原生指针

Rust提供多种类型的指针:

  1. 引用
  2. 原生指针
  3. 函数指针
  4. 智能指针

原生指针主要用于unsafe块中,直接使用原生指针是不安全的。

Rust支持两种原生指针:

  1. 不可变原生指针 *const T
  2. 可变原生指针 *mut T
fn main(){
	let mut x = 10;
	let ptr_x = &mut x as *mut i32;//将可变引用转换为可变原生指针ptr_x
	let y = Box::new(20);//在堆内存中存储数字20
	let ptr_y = &*y as *const i32;//转换为不可变原生指针ptr_y
	unsafe{//操作原生指针要使用unsafe块
		*ptr_x += *ptr_y;//对ptr_x、ptr_y指针解引用,求和
	}
	
	println!("x = {}",x);
}

never类型

即!(感叹号)。该类型用于表示永远不可能有返回值的计算类型。never类型可以强制转换成其他任何类型。

3.7 复合数据类型

Rust提供的复合数据类型有:

元组

fn main(){
	//定义元组
	let tuple:(&'static str,i32,char) = ("hello",-1,'s');
	println!("{:?}",tuple);//打印元组
	println!("tuple.1 = {}",tuple.1);
	println!("-------------------------");
	//利用元组让函数返回多个值
	//let支持模式匹配,所以可以用来解构元组
	let (x,y) = foo((2,3));//函数返回一个元组,通过let解构,元组第一位绑定到x,第二位绑定到y
	println!("x = {}",x);//可以直接使用x、y
	println!("y = {}",y);
	println!("-------------------------");
	//当元组只有一个值时,需要加逗号,即(0,)
	//前面讲到的单元类型就是一个空元组,即()
}

fn foo(x:(i32,i32)) -> (i32,i32){
	(x.0 + 1,x.1 + 1)
}

结构体,分三种:

  • 具名结构体
//结构体里面字段格式为name:type
//name是字段名称
//type是字段的类型
struct People{
    name:&'static str,
    gender:u32,
}
  • 元组结构体
//元组结构体后面要加分号
//访问元组结构体中的字段,使用圆点记号(.)
struct Color(i32,i32,i32);

fn main(){
    let color = Color(0,1,2);
    println!("{}",color.0);//类似于元组的使用方法
}
  • 单元结构体
//没有任何字段的结构体,称为单元结构体
struct Empty;

枚举体

//定义枚举体的关键字为Enum
//无参数枚举体
enum Number {
    Zero,
    One,
    Two,
}
//使用方法
let a = Number::One;

//类C枚举体
enum Color{
    Red = 0xff0000,
    Green = 0x00ff00,
    Blue = 0x0000ff, 
}


//带参数枚举体
enum IpAddr{
    V4(u8,u8,u8,u8),
    V6(String),
}

3.8 注释与打印

普通注释

//对整行注释

/*......*/对区块注释

文档注释

///,可以生成库文档,一般用于函数或结构体的说明,置于说明对象上方

//!,也可以生成库文档,一般用于说明整个模块的功能,置于模块文件的头部

格式化打印 

fn main(){
	let a = 6;
	//nothing代表Display
	println!("{}",1);
	//?代表Debug
	println!("{:?}",2);
	//o代表八进制
	println!("{:o}",3);
	//x代表十六进制小写
	println!("{:x}",4);
	//X代表十六进制大写
	println!("{:X}",5);
	//p代表指针
	println!("{:p}",&a);
	//b代表二进制
	println!("{:b}",7);
	//e代表指数小写
	println!("{:e}",3.1415926);
	//E代表指数大写
	println!("{:E}",3.1415926);
}
发布了27 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/drsonxu/article/details/99887581