语法基础
注释
行注释
let x = 5 // 绑定
块注释
出于某种原因,Rust中不太建议使用。但其实无所谓。
/*
let x = 42;
println!("{}", x);
*/
文档注释
使用 /// 。用于函数或结构体(字段)的说明,置于要说明的对象上方。文档注释内部可使用markdown格式的标记语法。
类似于javadoc,可以用rustdoc命令提取代码内的注释。
/// 输入一个数字。
/// 返回该数字加1后的值。
fn add_one(x: i32) -> i32 {
x + 1
}
模块注释
使用 //!
,用于说明当前模块的功能。置于模块文件的头部。
//! # 自定义Rust HTTP库。
//!
//! 该模块提供了HTTP网络编程相关功能。
语句
Rust使用 ;
作为语句的分隔符,这与Java一样。
另外,Rust是基于表达式的语言,这与Scala一样。即
每段代码块都是有值的。其值等于代码块最后一条语句的值。
例:rust中没有三目运算符(?:) ,因为不需要,直接这样这样使用。
let y = if x == 5 { 10 } else { 15 };
绑定初步
变量绑定是Rust中最复杂且最重要的概念。这里先做简单学习,后续深入。
// 变量绑定
let a1 = 5;
let a2:i32 = 5;
a1 = 10; // 不可变变量无法再赋值,该语句无法通过编译。
// 可变绑定
let mut b1 = 5;
b1 = 10;
- 使用
let
的变量,变量不可变。变量不可再次被“赋值”。 - 使用
let mut
的变量,变量可变。可以再次被“赋值”。
与Java的final不同,Rust中的不可变变量是指资源的不可变。
例:
let a = vec![1,2,3]; // vec![1,2,3]是不可变的。已经固定的值。
a.push(4); // 编译报错。
println!("{:?}", a);
必须要使用let mut
才可以对值做操作。
let mut a = vec![1,2,3];
a.push(4);
println!("{:?}", a); // 输出 [1, 2, 3, 4]
“不可变变量” 与“可变变量”的转换
let a = 5;
let mut b = a; // 不可变 -> 可变
b += 10;
println!("{:?},{:?}", a,b); // 输出5,15
let mut c = 10;
c += 10;
let d = c; // 不可变 -> 可变
println!("{:?},{:?}", c,d); // 输出20,20
多值“赋值”
类似Go语言的多值赋值。
// 不需要声明变量类型
let (a1,a2,a3) = (10,20,30);
println!("{:?},{:?},{:?}", a1,a2,a3);
// 声明变量类型
let (b1,b2,b3) : (bool,i32,bool)= (true,32,false);
println!("{:?},{:?},{:?}", b1,b2,b3);
// 混合let与let mut的变量绑定
let (c1,mut c2,c3) : (bool,i32,bool)= (true,32,false);
c2 += 10;
println!("{:?},{:?},{:?}", c1,c2,c3);
const 常量
Rust的const不是真正的变量。因为该常量变量不存在于内存中。而是在编译阶段直接嵌入了代码中。
const PI:f32 = 3.14;
基础类型
类型 | 值 | 说明 |
---|---|---|
布尔 | true或false | |
字符 | let c = 'c'; | 单Unicode字符,1个字符4个字节 |
有符号整数 | let x = 42; | 所有的符号整数 (i8, i16, i32, i64, isize) |
无符号整数 | let x:u8 = 255; | 无符号整数 (u8, u16, u32, u64, usize) |
浮点数 | let x:f64 = 1.23e+2; | 浮点数 (f32, f64) |
字符串 | let str = "Hello, world!"; let mut string = str.to_string(); |
最底层的是不定长类型str,更常用的是字符串切片&str和堆分配字符串String, 其中字符串切片是静态分配的,有固定的大小,并且不可变,而堆分配字符串是可变的。 |
数组 | let a = [0, 1, 2, 3, 4]; let mut ten_zeros: [i64; 10] = [0; 10]; |
具有固定大小,并且元素都是同种类型,可表示为[T; N]。 |
切片 | let a = [0, 1, 2, 3, 4]; let middle = &a[1..4]; |
引用一个数组的部分数据并且不需要拷贝,可表示为&[T]。 |
元组 | let tuple: (i32, &str) = (50, "hello"); let (fifty, _) = tuple; let hello = tuple.1; |
具有固定大小的有序列表,每个元素都有自己的类型,通过解构或者索引来获得每个元素的值。 |
指针 | let x = 5; let raw = &x as const i32; let points_at = unsafe { raw }; |
最底层的是裸指针const T和mut T,但解引用它们是不安全的,必须放到unsafe块里。 |
函数 | fn foo(x: i32) -> i32 { x } let bar: fn(i32) -> i32 = foo; |
具有函数类型的变量实质上是一个函数指针。 |
元类型 | () | 其唯一的值也是()。 |
对于数值
数值类型可以使用_分隔符来增加可读性。
对于字符
Rust还支持单字节字符b'H'以及单字节字符串b"Hello",仅限制于ASCII字符。 此外,还可以使用r#"..."#标记来表示原始字符串,不需要对特殊字符进行转义。
对于字符串
使用&符号将String类型转换成&str类型很廉价, 但是使用to_string()方法将&str转换到* String类型涉及到分配内存, 除非很有必要否则不要这么做。
对于数组
数组的长度是不可变的,动态的数组称为Vec (vector),可以使用宏vec!创建。
对于元组
元组可以使用==和!=运算符来判断是否相同。 不多于32个元素的数组和不多于12个元素的元组在值传递时是自动复制的。
类型转换
Rust不提供原生类型之间的隐式转换,只能使用as关键字显式转换。
别名
可以使用type关键字定义某个类型的别名,并且应该采用驼峰命名法。