Rust学习(二)——rust基础语法Ⅰ:
Rust学习(二)——rust基础语法Ⅰ:
1、关键字:
了解编程语言的同学都清楚,关键字在一门编程语言中的意义,所谓关键字就是语言的创造者及后续开发者们,以及定义好的具有特殊含义和作用的单词,需要注意的是在变量及函数等名命时要避开这些关键字,以避免可能出现逻辑冲突,每种编程语言所拥有的关键字数量并不相同,Rust目前有39个关键字:
Self enum match super as
extern mod trait async false
move true await fn mut
type break for pub union
const if ref unsafe continue
impl return use crate in
self where dyn let static
while else loop struct # 注意Self和self是两个不同的关键字
很多关键字和其他编程语言种的关键字功能类似,比如:for,move,if等,但是也有一些独特的关键字,体现了语言的设计者的精妙构思,比如match在Rust种功能强大,但是在C/C++中对应的switch的功能就相对偏弱。
2、注释:
在编程中注释的作用自然不必多说,就有一句著名的格言展示了注释的重要性:一个程序员在编程时,只有他和上帝知道代码的作用,过了三天就只有上帝知道这段代码的作用了!(doge),因此在编程中加入注释,可以帮助阅读代码的人(也包括作者)更好的理解代码编写过程中的复杂逻辑,从而做出针对性的优化,Rust和C/C++、python等语言相比注释功能更加完整和强大!
Rust的注释有两大类:普通注释和文档注释。
①普通注释:
rust提供了单行和多行普通注释两种方法(和C/C++保持一样):
// 单行注释
/*
*
*多行注释
*多行注释
*
*/
②文档注释:
rust非常关注文档和测试,因此提供了专门的文档注释,用于在注释中直接编写文档和测试代码,同时Rust文档采用的时Markdown格式,因此在编写测试文档时,需要注意使用Markdown形式:
//! 生成库文档,用于说明整个模块的功能,一般置于模块开头
/// 生成库文档,用于说明函数和结构体功能,一般置于说明对象的开头
//! Math 模块
//!
/// #add 函数
/// 该函数为求和函数
///
/// # Example
/// use math::add;
/// assert_eq!(3, add(1, 2));
fn add(x: i32, y: i32) -> i32 {
// 求和
x + y
}
3、Rust名命风格:
名命风格并不是强制要求,但是应该被看做时一种规范而被遵循。Rust推荐采用驼峰式命名(UpperCamelCase)来表示类级别的内容,而采用蛇形命名(snake_case)类描述值级别的内容,可见下表:
项 约定
包 snake_case
类型 UpperCamelCase
特性 UpperCamelCase
枚举 UpperCamelCase
函数 snake_case
方法 snake_case
构造函数 (无特殊要求)或者new
转换函数 (无特殊要求)
宏 snake_case
局部变量 SCREAMING_SNAKE_CASE
静态变量 SCREAMING_SNAKE_CASE
常量 sanke_case
类型参数 UpperCamelCase
生命周期 lowercase
下面这个例子给大家提供了一个很好的参考:
// 枚举
enum Result<T,E> {
Ok(T),
Err(E),
}
// 特性trait
pub trait From<T> {
fn from<T> -> Self;
}
// 结构体:
struct Rectangle {
height: i32,
width: i32,
}
impl Rectangle {
//构造函数
fn new(height: i32, width: i32) ->Self {
Self {height, width}
}
// 函数
fn calc_area(&self) ->i32 {
self.height * self.width
}
}
// 静态变量和常量
static NAME: &str = "kew";
const AGE: i32 = 25;
// 宏定义:
macro_rules! add{
($a:expr, $b:expr) => {
{
$a + $b
}
}
}
// 变量及宏使用:
let sum_of_nums = add!(1,2);
4、常量:
Rust中的常量和C++中的常量基本一致,特点是不可修改,不可覆盖,使用const关键字定义:
//常量定义,类似于C/C++中的#define(宏定义)
const AGE: i32 = 1984;
// AGE = 1985; 报错, 常量不允许被修改
// const AGE: i32 = 1996; 报错,AGE已经被定义过,不能被覆盖
5、变量:
rust中变量使用let定义,变量是一个绑定到一个名称且允许改变(可覆盖)的值,但在Rust中有一些不同,默认直接使用let定义的变量不可修改,使用mut关键字方可修改:
let x: f64 = 3.14;
// x = 6.28; 报错,变量不可修改
let x: f64 = 6.28; //变量可以被覆盖
let mut y: f64 = 256.01;
y = 3.28;
let y: f64 = 2024; // 使用mut关键字之后变量可修改,可覆盖。
6、静态变量:
静态变量是一种特殊的变量,可以被修改,但是不能被覆盖,同时其是否可修改同样取决于是否使用mut关键字:
static NAME: &str = "rust";
// NAME = "new"; 报错,未使用mut不可以被改变
static mut NUM: i32 = 12;
unsafe {
NUM += 1; // 可以看到static mut 修改是在unsafe中完成的,所以日常开发中使用较少
}
// static NAME: &str = "Cargo"; 报错,静态变量不可覆盖
// static NUM: i32 = 13; 错误,静态变量不可覆盖
7、数据类型:
学习一门编程语言,一定会从数据类型入手,这点就好比学习C语言的char、array类型,python的整型、浮点型等,如果学习一门编程语言却不知道数据类型,未免太不专业了!
数据类型是一门语言的基础,所有复杂的模块都是由基础数据类型构建而来的,Rust的基础数据类型分为标量类型和符合类型两大类型,标量类型代表一个单独的值,复合类型则是将多个值组合成一个值的类型(有点绕,不要着急,下文会仔细解释!)
(1)标量类型:
Rust中有四种基本的标量类型:整型、浮点型、布尔型和字符型。
①整型:
整型即整数:没有小数部分的的数字,根据长度和符号,可分为12类,其中i表示有符号整型,u表示无符号整型:
长度 有符号 无符号
8 i8 u8
16 i16 u16
32 i32 u32
64 i64 u64
128 i128 u128
arch isize usize
这里需要特别指出,isize和usize是指和计算机架构相匹配的整型长度,如64位机器isize和usize都是64位长度,32位机器isize和usize都是32位长度的。
②浮点数:
rust中的浮点数分为:f32和f64两种类型(都是有符号的),默认为64位。
③布尔类型:
和其他类型一致,都是true和false两类(doge)。
④字符型:
rust的字符和C语言中的char是一致的,注意:字符使用单引号声明,而字符串使用双引号声明,字符串属于数组类型。
// Unicode 标量:字符型
let c = 'a';
// 数组字符串:
let str_c = "hello rust";
(2)复合类型:
①元组:
元组是一种能够将多个类型的数据值组合成复合值得类型,即所谓将多个值合并为一个值。一旦声明元组得长度就不可改变,元组使用圆括号包裹,并用逗号分隔。为了从元组中获取值,你可以使用模式匹配和点符号(类似于其他语言得索引,从下标0开始)。
let tup: (i32, i32,i64) = (1, 2, 3);
// 使用模式匹配:
let (x, y, z) = tup;
let tup2:(i32, i32, i32) = (2,3,4);
let zero = tup2.0 // 点符号获取值
②数组:
Rust中得数组和C/C++中得数组类似,数组中得每一个元素必须保持一致,且长度也不可以改变。但是Rust为我们提供了可变数组,使用Vec定义得数组,允许增长长度,大部分时候,我们使用得也是Vec定义得数组:
// 定义数组
let numbers = ["a", "b", "c"];
let digits[i32;5] = [0, 1, 2, 3, 4, 5]; // 通过[type;num]定义数组
let zeros = [0;5]; //创建一个包含5个0得数组
let bundary = numbers[0];
(3)数据类型转换:
Rust中得数据类型大多数是可以互相转换得,比如将i8转换为i16就是合理转换,但rust中不支持原生类型之间得隐式转换(将字符型转换为浮点型),必须使用as关键字进行显性转换。
fn main() {
let decimal:f32 = 61.234;
// let integer: u32 = decimal; 错误!不能进行隐式转换
let integer = decimal as u32; //正确!,使用as进行显示转换
}
更加复杂得类型中,Rust提供了From和Info两个trait进行转换:(trait是一个难点,后面会具体介绍)
pub trait From<T> {
fn from<T> ->Self;
}
pub trait Into<T> {
fn into<T> ->Self;
}
struct Complex {
real:i32,
imag:i32
}
impl From<i32> for Complex {
fn from(real:i32) ->Self {
Self {real, imag:0}
}
}
fn main() {
let c1: Complex = Complex::from(2);
let c2: Complex = 2.into();
println!("c1:{:?}, c2:{:?}", c1, c2);
}