COMP6991 Solving Modern Programming Problems with Rust
记录RUST相关基本语法。
RUST//不可变变量
let s = 100;
//可变变量(mutable)
let mut s = 100;
//类型变量
let mut s = String::new();
重影是指变量的名称可以被重新使用的机制(多次重复使用let
):
RUSTfn main() {
let x = 5;
let x = x + 1;
let x = x * 2;
println!("The value of x is: {}", x);
}
重影与可变变量的赋值不是一个概念,重影是指用同一个名字重新代表另一个变量实体。
重影变量的类型、可变属性和值都可以变化。
可变变量赋值仅能发生值变化。
在同一范围内多次声明同名变量,后声明的变量会隐藏(遮蔽)前面的同名变量。这意味着在同一作用域内,后声明的变量会覆盖前面的同名变量,而前面的同名变量则不再可见。
需要注意的是,在不同的作用域中,不同的x
在事实上是同时存在的,而不是后者取代前者的关系。
RUSTlet x = 42;
{
let x = 123;
println!("The value is: {x:?}");
}
println!("{x}");
输出的结果是:
The value is: 123 42
数组创建时声明类型与长度。也可以不写,编译器会自动处理。
RUSTfn main() {
let my_array: [i32; 5] = [
1,
2,
3,
4,
5,
]
}
使用vec!
创建VEC,并且能够使用push
添加变量。
RUSTlet mut my_vec = vec![1, 2, 3];
my_vec.push(42);
可以直接将一个变量内部声明多个变量。
RUSTlet my_tuple: (bool, i32, char) = (true, 42, 'z');
let my_tuple: (i32) = (7);
let unit_tuple = ();
注意:空tuple一般不能作为bool变量的判断。
RUSTlet unit_tuple = ();
//非法,不可编译通过
if unit_tuple {
}
//合法
if unit_tuple == () {
}
首先枚举不同种类的选项,之后可以自由使用。
RUSTenum CarBrand {
Toyota,
Nissan,
Subaru,
}
fn main() {
let brand: CarBrand = CarBrand::Toyota;
//注意,以下写法是不合法的
let brand = CarBrand::Toyota;
}
同时,这些类型一样可以声明成不同的变量类型,之后直接赋值(变量类型请见下文)。
RUSTenum CarBrand {
Toyota(i32),
Nissan(String),
Subaru,
}
fn main() {
let brand: CarBrand = CarBrand::Toyota(42);
let brand: CarBrand = CarBrand::Nissan(String::form("HelloWorld"));
}
Option
是一个枚举类型,用于表示一个值可能存在也可能不存在的情况。这个类型被广泛用于处理可能为空的情况,类似于其他语言中的可选类型或者空安全类型。Option
枚举有两个可能的值:
Some(T)
: 表示值存在,并且包含了类型为 T 的具体值。None
: 表示值不存在,没有具体的值。这个模式允许程序员在可能返回空值的情况下更好地处理代码,以避免空指针异常或者其他类似的错误。
例如,一个简单的函数可能会返回一个Option
类型,表明它可能返回一个值,也可能返回空值:
RUSTfn main() {
let some_value: Option<i32> = Some(5); // 创建一个包含整数值的 Some
let no_value: Option<i32> = None; // 创建一个空的 Option
match some_value {
Some(value) => println!("Value is: {}", value), // 如果存在值,则打印值
None => println!("No value!"), // 如果不存在值,则打印"无值"
}
match no_value {
Some(value) => println!("Value is: {}", value), // 如果存在值,则打印值
None => println!("No value!"), // 如果不存在值,则打印"无值"
}
}
在这个简短的示例中,我们定义了两个 Option<i32>
类型的变量:some_value
和no_value
。
some_value
包含了一个具体的整数值5
,而no_value
则是一个空的Option
。然后,我们使用match
来检查这些变量,如果存在值,则打印该值,否则打印 "无值"。
经典的变量有以下几种:
char, short, int, long, long long i8, i16, i32, i64, i128 u8, u16, u32, u64, u128 float, double f32, f64
由于RUST的运行环境的位数不同,例如在32位和64位的机器上,变量的位数可能会发生变化,因此规定变量的位数是很有必要的。
规定位数的方式:
RUSTlet x: u8 = 42;
变量之间也可以进行强制类型转换,但是存在风险(dirty way)。
RUSTlet x: u8 = 42;
let y: i32 = x as i32;
推荐的方法是使用into
来进行风险预警。
RUSTlet x: i32 = 1231231123;
let y: u8 = x.into();
如果可能会出现丢失数据的情况发生,它会报错并发出预警。
发出自定义预警的方法:
RUSTlet x: i32 = 1231231123;
let y: u8 = x.into().expect("Number was too big");
这样在触发报警的时候会抛出“Number was too big”。
大括号的返回值只取决于最后一行。
RUSTlet judge = {
let mut a = 4;
a = a * a;
a += 12;
//最终给judge赋的值
a/4
};
标准形式:
RUSTfn main() {
let my_array = [10, 20, 30, 40, 50];
for i in 0..5 {
println!("my_array[{}] = {}", i, my_array[i]);
}
}
但RUST也支持数组元素直接访问。
RUSTlet my_array = [
1,
2,
3,
4,
5,
]
for elem in my_array {
println!("{elem}");
}
RUSTlet my_string = String::form("HelloWorld");
let output_string = my_string;
//能够正常输出
println!("{output_string}");
//会报错
println!("{my_string}");
String 类型是可变的、拥有所有权的类型,而在你的代码中,你把 my_string 绑定到了一个新的 String 实例上,然后尝试再次使用 my_string 来打印其值,这违反了所有权规则。
在 Rust 中,所有权规则保证了内存安全和避免了数据竞争。当你把 my_string 赋值给 output_string 后,所有权被转移了,output_string 拥有了 my_string 的所有权,而 my_string 不再有效。因此,尝试打印 my_string 的值会导致编译错误,因为它已经无效。
要修复这个问题,你可以通过使用 clone() 方法来克隆 my_string,以保留原始值并创建一个新的 String 实例,而不是直接将所有权转移给另一个变量。例如:
RUSTlet my_string = String::from("HelloWorld");
let output_string = my_string.clone();
println!("{output_string}");
println!("{my_string}");
因此,在RUST中,进行复制(Copy)操作时一定要考虑所有权的问题。
本文作者:Jeff Wu
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!