参考: 菜鸟教程
1 输出到命令行
这不得打印个螃蟹
// 代码来自官方入门教程
// ferris_say需要另外安装
use ferris_says::say;
use std::io::{stdout, BufWriter};
fn main() {
let stdout: std::io::Stdout = stdout();
let msg: String = String::from("Hello fellow Rustaceans!");
let width: usize = msg.chars().count();
let mut writer: BufWriter<std::io::StdoutLock> = BufWriter::new(stdout.lock());
say(msg.as_bytes(), width, &mut writer).unwrap();
}
cargo run
查看螃蟹。它叫Ferris
,乃Rust社区的吉祥物。
老规矩打印“Hello world!”
这就需要用到print!( )
和println!( )
两个宏规则
println!( )
输出后会换行但print!( )
不会
提到输出就不得不提格式化字符串了,Rust的占位符{}
fn main() {
let msg: &str = "Hello world!";
println!("Hello world!");
// {}内填数字,把格式字符串之后的可变参数当数组来用(下标也是从零开始)
print!("{0}, {0}", msg); // 格式化字符串
print!(" Very good!");
}
2 变量
2.1 不可变的变量
Rust是强类型语言,但具有自动判断变量类型的能力
声明变量,需要
let
(写JavaScript的时候用过诶)
单单使用个let
声明的变量,被官方称为"不可变变量"
- 在确定变量类型后,不能把其他类型的值赋给它
- Rust不允许精度有损失的自动数据类型转换
- 记住了!!!这是它是“不可变变量”
//虽然Rust会自动判断变量类型但是手动加上比较好
//整型默认是 32位,手动写成 64位,变量取值范围大大的不一样
let hell: i32 = 234;
let hell: i64 = 1234;
let msg: &str = "Hello hell!";
只需要加一个
mut
就能是”不可变变量“可变啦
fn main() {
let mut msg: &str = "Hello world!"; //①
// print!("{}", msg);
msg = "Hello hell!";
print!("{0}, {0}", msg); //②
print!(" Very good!");
}
上面的代码运行后会出现警告
warning: value assigned to msg
is never read
说是①位置的 msg
的值永远无法读取到。因为在打印之前修改了它的值,这样变量最开始的值就访问不到了,把注释取消,警告就会消失
2.2 常量和不可变变量的区别
下面代码在Rust中是合法,但是①位置的
hell
未被使用,所以会有警告
warning: unused variable:hell
这里操作叫重影
fn main() {
let hell: i32 = 123; // ①
let hell: i32 = 234; // ②
print!("{}", hell);
}
但是如果是常量,那就不行了,得报错了
error[E0005]: refutable pattern in local binding
//这么写是错误的
fn main() {
const hell: i32 = 123;
let hell: i32 = 234;
print!("{}", hell);
}
2.3 重影
变量名可以重新使用的机制
和其他语言的“重写
”或“重载
”是不一样的
重影是指用同一个名字重新代表另一个变量实体,其类型、可变属性和值都可以改变。
可变变量赋值就不一样了,赋值只能改变值
这样整是会报错的
error[E0308]: mismatched types
fn main() {
let mut welcome: &str = "Hello hell";
let len: i32 = welcome.len().try_into().unwrap();
println!("The length of welcome is {}", len);
welcome = welcome.len();
println!("The length of welcome is {}", welcome);
}
这个是会
Rust
不会帮你自动转换类型,需要解锁
可以使用as
或者try_into
fn main() {
let welcome: &str = "Hello hell";
//len()返回的是usize
//let len: i32 = welcome.len() as i32;
let len: i32 = welcome.len().try_into().unwrap();
println!("The length of welcome is {}", len);
}
// The length of welcome is 10
2.4 数据类型
整数型 整数还能加下划线
//这是合法的
let a: i32 = 199_0000;
let a: i32 = 199_0_0_0;
//写成这样也没毛病,不过加下划线是为更容易判断数据大概多大的
浮点型32位浮点数(
f32
)和64位浮点数(f64
)
我的电脑是默认64位的
布尔型
true
和false
字符串
char
一些简单的数学运算
rust不支持自增自减(++, --)
fn main() {
let mut sum: i32 = 5 + 10;
println!("{}", sum);
sum += 1;
let dif: f64 = 9.5 - 1.2;
let mul: i32 = 7 * 10;
let rem: i32 = 43 % 3;
println!("{}, {}, {}, {}", sum, dif, mul, rem);
}
//15
//16, 8.3, 70, 1
复合类型 元组
()
数组[]
let msg = ['H'; 5];
//等价于let msg = ['H', 'H', 'H', 'H', 'H'];
let ele = msg[0];
println!("{}", ele);
let array: [[i32; 3]; 2] = [[1,2,3], [3,4,2]];
println!("{}", array[0][0]);
3 函数
fn
<函数名> (<参数>) <函数体>
函数体表达式不能使用return
fn main() {
let y = { // 表达式块 函数体表达式
let x = 4;
x + 2 // 表达式, 它的结果是整个表达式所代表的值
};
//嵌套的函数
//跟Python的挺像的, 不过Python就一个样子在哪
fn print_var(var: i32) -> i32 {
// print!("OK... ");
// var + 2
return var + 2;
}
print(print_var(y));
print(y);
println!("Value of y is {}", y);
}
fn print(x: i32) {
// println!("Hello, world!");
println!("{}", x);
}
4 条件
条件不需要向C语言一样加
()
fn main() {
let msg: &str = "hello";
let _msg_other: &str;
if msg == "hello" {
_msg_other = "hell";
}
else if msg == "Hello"{
_msg_other = "Boom"; // 如果注释这句,将会报错
// _msg_other可能会未初始化
println!("HHHH");
}
else {
_msg_other = "world";
}
println!("{}, {}", msg, _msg_other);
}
条件表达式必须是
bool
类型
fn main() {
let number = 3;
if number {
// 报错,expected `bool`, found integerrustc(E0308)
println!("Yes");
}
}
可以实现类似三元条件运算表达式(A?B:C)的效果
{}中的表达式必须是同一类型不然会报错
error:if
andelse
have incompatible types
少了else{} 也会报错的
error:if
may be missing anelse
clause
if
expressions withoutelse
evaluate to()
fn main() {
let r = 3;
let msg = if r > 0 { "Hello hell!" } else { "haha" };
println!("{}", msg);
}
5 循环
5.1 while
fn main() {
let mut index: i32 = 0;
// let mut index: usize = 0;
let msg: [&str; 4] = ["Hell", "Hello", "World", "Judy"];
while index != 4 {
// 下标的类型必须是 usize
println!("{}", msg[index as usize]);
index += 1;
}
println!("EXIT");
}
运行结果:
Hell
Hello
World
Judy
EXIT
5.2 for
for 循环是最常用的循环结构,常用来遍历一个线性数据结构
fn main() {
let msg: [&str; 4] = ["Hell", "Hello", "World", "Judy"];
// msg.iter 表示是 msg的迭代器
for i in msg.iter() {
println!("{}", i);
}
}
fn main() {
let msg: [&str; 4] = ["Hell", "Hello", "World", "Judy"];
for i in 0..4 {
println!("msg[{}] = {}", i, msg[i]);
}
}
运行结果:
msg[0] = Hell
msg[1] = Hello
msg[2] = World
msg[3] = Judy
5.3 loop
Rust 语言有原生的无限循环结构
fn main() {
let msg = ["Hell", "Hello", "World", "Judy", "EOF"];
let mut i: usize = 0;
loop {
let str: &str = msg[i];
if str == "EOF" {
break i;
}
println!("msg[{}] = {}", i, str);
i += 1;
};
}
运行结果:
msg[0] = Hell
msg[1] = Hello
msg[2] = World
msg[3] = Judy
loop 循环可以通过 break 关键字类似于 return 一样使整个循环退出并给予外部一个返回值。因为 loop 这样的循环常被用来当作查找工具使用,如果找到了某个东西当然要将这个结果交出去
fn main() {
let msg = ["Hell", "Hello", "World", "Judy", "EOF"];
let mut i: usize = 0;
let location: usize = loop {
let str: &str = msg[i];
if str == "EOF" {
break i;
}
i += 1;
};
println!("\"BOF\" 的索引是 {}", location);
}
运行结果:
"BOF" 的索引是 4
6 所有权
所有权规则
- Rust 中的每个值都有一个变量,称为其所有者。
- 一次只能有一个所有者。(某段内存只能被最后的变量名所有,前面声明过的变量都作废,这有效的避免被多个变量释放的问题,而且该操作是在编译期就可以检查到的,这策略可在编译期就能有效的避免空指针问题。)
- 当所有者不在程序运行范围时,该值将被删除。(Rust对栈内存和堆内存一视同仁,超出作用域一律释放)