通用编程概念
3.1. 变量和可变性
可变性
{% hint style="info" %}
rust 特点:“变量不可变”。如何记住呢,可以这样理解,生成一个变量用的是let,本来也没说可以变。可以想象一个稳定的真理世界,里边都是不变的永恒的东西,这样就觉得很安全吧。如果要定义一个东西确实可以变,那就再加上 mut。
不可变变量
let x = 5;
可变变量
let mut x = 5;
常量:常量只能设置为常量表达式,而不能是函数调用的结果或是只能在运行时计算得到的值。
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
遮蔽
{% hint style="info" %}
rust 特点:“变量重复声明”。如何记住呢(我的理解):
- 对于 c,一个作用域中我们不能两次声明变量 x。我们的内存空间就很稳定,但是程序写的不方便,没用的东西没办法及时丢掉。
- 对于 python,可以重复的创建同样变量名的 x,每次后边就会取代前边。这样程序很好写,但是由于 python 是解释型语言,性能就会很差。(可以发现变量每变一次地址都不一样)。而且 Python 由于他的“逐行解释”,不能支持遮蔽了。
s = "Hello"
print(id(s)) # 4534146672
s = s+" World"
print(id(s)) # 4534146544
x = 1
print(id(x)) # 4531576152
x = x+1
print(id(x)) # 4531576184
y = 1
print(id(y)) # 4531576152
y += 1
print(id(y)) # 4531576184
- 对于 rust,我们可以重复声明变量x,让程序好写。然后通过编译环节来提高性能,这样就能精准的控制每个变量的作用域了。
fn main() {
let a = "String";
println!("{a}"); // String
let a = a.len();
println!("{a}"); // 6
}
遮蔽就是内部的作用域的变量传不出去,但可以访问外部的作用域的变量。很多语言都可以做到:
#include <stdio.h>
int main()
{
int i = 1;
{
int j = i;
int i = j + 1;
printf("%d\n", i); // 2
}
printf("%d\n", i); // 1
return 0;
}
x = 1
def f():
x = x+1 # UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
print(x+1)
f()
print(x)
fn main() {
let a = "String";
{
let a = a.len();
println!("{a}"); // 6let a = a.len();
}
println!("{a}"); // String
}
总得来讲,Rust 既可以像 C 一样遮蔽,又可以像 Python 一样好用。
3.2. 数据类型
标量类型
整型、浮点型、布尔型和字符
整型类型
| 长度 | 有符号类型 | 无符号类型 |
|---|---|---|
| 8 位 | i8 |
u8 |
| 16 位 | i16 |
u16 |
| 32 位 | i32 |
u32 |
| 64 位 | i64 |
u64 |
| 128 位 | i128 |
u128 |
| arch | isize |
usize |
isize 和 usize 类型取决于程序运行的计算机体系结构,在表中表示为“arch”:若使用 64 位架构系统则为 64 位,若使用 32 位架构系统则为 32 位。
整形字面量
| 数字字面量 | 示例 |
|---|---|
| 十进制 | 98_222 |
| 十六进制 | 0xff |
| 八进制 | 0o77 |
| 二进制 | 0b1111_0000 |
字节 (仅限于 u8) |
b'A' |
浮点类型
默认为f64,也可以声明成f32
数字运算
Rust 除法整形不取小数,和 C 一样。(Python 除法整形会自动转换成小数)
布尔类型
true,false。和 C 一样。
字符类型
大小为 3 字节。C 是一字节。Python 不一定。
{% tabs %}
{% tab title="Rust" %}
统一采用Unicode
fn main() {
let c1 = 'a';
println!(
"The size of the char 'a' is {} bytes",
std::mem::size_of_val(&c1)
);
let c2 = 'π';
println!(
"The size of the char 'π' is {} bytes",
std::mem::size_of_val(&c2)
);
let c3 = '中';
println!(
"The size of the char '中' is {} bytes",
std::mem::size_of_val(&c3)
);
let c4 = '😻';
println!(
"The size of the char '😻' is {} bytes",
std::mem::size_of_val(&c4)
);
let c5 = "🀄️";
println!(
"The size of the string '🀄️' is {} bytes",
std::mem::size_of_val(&c5)
);
}
// The size of the char 'a' is 4 bytes
// The size of the char 'π' is 4 bytes
// The size of the char '中' is 4 bytes
// The size of the char '😻' is 4 bytes
// The size of the string '🀄️' is 16 bytes
// note: this `🀄` is followed by the combining mark `\u{fe0f}`
// --> src/main.rs:17:15
// |
// 17 | let c4 = '🀄️';
// | ^^
// help: if you meant to write a string literal, use double quotes
// |
// 17 | let c4 = "🀄️";
// | ~ ~
{% tab title="Python" %}
一个字符不一定多大
def get_byte_size(char):
# 尝试将字符编码为UTF-8
try:
utf8_bytes = char.encode('utf-8')
# 返回字符编码后的字节大小
return len(utf8_bytes)
except UnicodeEncodeError:
# 如果字符不能被编码为UTF-8,返回一个错误消息或默认值
return "字符不能被编码为UTF-8"
print(f"字符 'a' 的字节大小是:{get_byte_size('a')}")
print(f"字符 'π' 的字节大小是:{get_byte_size('π')}")
print(f"字符 '中' 的字节大小是:{get_byte_size('中')}")
print(f"字符 '😻' 的字节大小是:{get_byte_size('😻')}")
print(f"字符 '🀄️' 的字节大小是:{get_byte_size('🀄️')}")
# 字符 'a' 的字节大小是:1
# 字符 'π' 的字节大小是:2
# 字符 '中' 的字节大小是:3
# 字符 '😻' 的字节大小是:4
# 字符 '🀄️' 的字节大小是:7
复合类型
复合类型(compound type)可以将多个值组合成一个类型。Rust 有两种基本的复合类型:元组(tuple)和数组(array)。
元组
fn main() {
let t: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = t; // 解构
let five_hundred = t.0; // 从 0 开始索引
let six_point_four = t.1;
let one = t.2;
}
数组
fn main() {
let a = [1, 2, 3, 4, 5]; // 1,2,3,4,5
println!("{} {} {} {} {}", a[0], a[1], a[2], a[3], a[4]);
let a: [i32; 5] = [1, 2, 3, 4, 5]; // 1,2,3,4,5
println!("{} {} {} {} {}", a[0], a[1], a[2], a[3], a[4]);
let a = [3; 5]; // 3,3,3,3,3
println!("{} {} {} {} {}", a[0], a[1], a[2], a[3], a[4]);
}
3.3. 函数
函数定义
用小驼峰命名法
参数
fn main() {
print_labeled_measurement(5, 'h');
}
fn print_labeled_measurement(value: i32, unit_label: char) {
println!("The measurement is: {}{}", value, unit_label);
}
语句
{% hint style="success" %}
这是 Rust 的精髓之一!一切皆表达式!函数,if,{}都是
fn main() {
let y = { // {...}就是表达式了,有返回值
let x = 3;
x + 1 // 没有分号就自动当成 return
}; // 注意,let 没有返回值
println!("The value of y is: {}", y);
}
// The value of y is: 4
函数的 return 可以用这种语法糖来完成
fn main() {
let x = plus_one(5);
println!("The value of x is: {}", x);
}
fn plus_one(x: i32) -> i32 {
x + 1
}
3.4. 控制流
if 表达式
最基础的 if
fn main() {
let number = 6;
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
}
if 的条件必须是 bool,rust 不会自动把 int 转成 bool
fn main() {
let number = 3;
if number { // Wrong!
if number != 0 { // You can do this!
println!("number was three");
}
}
let + if
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {}", number); // 5
}
let + if 也要注意相同的返回类型
fn main() {
let condition = true;
let number = if condition { 5 } else { "six" }; // Wrong!
println!("The value of number is: {}", number);
}
循环
loop
fn main() {
let mut count = 0;
loop {
if count == 10 {
break;
}
count += 1;
}
}
break 可以指定跳到外边的某一层
fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {}", count);
let mut remaining = 10;
loop {
println!("remaining = {}", remaining);
if remaining == 9 {
break; // break本层
}
if count == 2 {
break 'counting_up; // break指定层
}
remaining -= 1;
}
count += 1;
}
println!("End count = {}", count);
}
//count = 0
//remaining = 10
//remaining = 9
//count = 1
//remaining = 10
//remaining = 9
//count = 2
//remaining = 10
//End count = 2
循环 + 表达式,用 break 作为 return
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {}", result); // 20
}
while
fn main() {
let mut number = 3;
while number != 0 {
println!("{}!", number);
number -= 1;
}
println!("LIFTOFF!!!");
}
for
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {}", element);
}
}
for + 倒序
fn main() {
for number in (1..4).rev() { // 左闭右开
println!("{}!", number);
}
println!("LIFTOFF!!!");
}
//3!
//2!
//1!
//LIFTOFF!!!