半小时学习 Rust
原文地址
谷歌翻译
- [x] Item 1
- [x] Item 1.1
- [x] Item 2 为了提高编程语言的流利程度,我们必须大量阅读编程语言。但是,如果你不知道它的意思,又怎么能大量阅读呢?
在本文中,我不会只关注一两个概念,而是会尽可能多地介绍 Rust 片段,并解释其中包含的关键字和符号的含义。
准备好了吗?走起!
let
引入一个变量绑定:
let x; // 声明 "x"
x = 42; // 将 42 赋值给 "x"
这也可以写成一行:
let x = 42;
你可以通过:
明确变量类型,一个类型声明:
let x: i32; // `i32` 是带符号的 32 位整数
x = 42;
// 这里有 i8, i16, i32, i64, i128
// 还有无符号的 u8, u16, u32, u64, u128
这也可以写成一行:
let x: i32 = 42;
如果您声明了一个名称并在稍后将其初始化,编译器将阻止您在初始化之前使用它。
let x;
x = 42;
foobar(x); // 这里将推断出 `x` 的类型
下划线 _ 是一个特殊的名称,或者说,是一个 "无名 "的名称。它的基本意思是扔掉某些东西:
// 因为 42 是一个常量,所以这样做没有*作用
let _ = 42;
// 这将调用 `get_thing` 但会丢弃其结果
let _ = get_thine();
以下划线开头的名称都是常规名称,只是编译器不会警告它们未被使用:
// 我们最终可能会使用 `_x`,但我们的代码还在编写中。
// 我们只是想暂时消除编译器的警告。
let _x = 42;
可以引入具有相同名称的单独绑定 - 您可以隐藏变量绑定:
let x = 13;
let x = x + 3;
// 在该行之后使用 `x` 仅引用第二个 `x`
// 第一个 `x` 已经不存在了
Rust 有元组,您可以将其视为 "不同类型值的固定长度集合"。
let pair = ('a', 17);
pair.0; // 这里是 'a'
pair.1; // 这里是 17
如果我们真的想注释配对的类型,我们可以这样写:
let pair: (char, i32) = ('a', 17);
在执行任务时,可以对元组进行去结构化处理(解构),即把它们分解成各自的字段:
let (some_char, some_int) = ('a', 17);
// 现在, `some_char` 是 'a',`some_int` 是 17
当一个函数返回一个元祖时是非常有用的:
let (left, right) = slice.split_at(middle);
当然,当解构一个元祖时, _
可以用作丢弃一部分:
let (_, right) = slice.split_at(middle);
分号;
标记语句的结束:
let x = 3;
let y = 5;
let z = y + x;
这就意味着语句可以跨越多行:
let x = vec![1, 2, 3, 4, 5, 6, 7, 8]
.iter()
.map(|x| x + 3)
.fold(0, |x, y| x + y);
(我们稍后会讨论它们的实际含义)。
fn
声明一个函数
这里是一个没有返回值的函数:
fn greet() {
println!("Hi there!");
}
下面是一个返回 32 位有符号整数的函数。箭头->
表示他的返回类型:
fn pair_dice_roll() -> i32 {
4
}
一对括号声明一个块,它有自己的作用域:
// 先打印 "in",然后 "out"
fn main() {
let x = "out";
{
// 这里是一个不同的 `x`
let x = "in";
println!("{}", x);
}
println!("{}", x);
}
块也是表达式, 意味着结果是一个值
let x = 42;
let x = { 42 };
在一个块内, 可以有多行语句:
let x = {
let y = 1;
let z = 2;
y + z // 尾行, 整个块的结果赋值给了 `x`
};
这就是为什么 "省略函数结尾的分号 "等同于返回,即它们是等价的:
fn pair_dice_roll() -> i32 {
return 4;
}
fn pair_dice_roll() -> i32 {
4
}
if
条件也是表达式:
fn pair_dice_roll() -> i32 {
if feeling_lucky {
6
} else {
4
}
}
match
也是表达式:
fn pair_dice_roll() -> i32 {
match feeling_lucky {
true => 6,
false => 4,
}
}
.
点通常用来访问字段值
let a = (10, 20);
a.0; // 10
let amos = get_come_struct();
amos.nickname; // "fasterthanlime"
或者访问一个值的方法:
let nick = "fasterthanlime";
nick.len(); // nick 的长度 14
两个冒号 ::
,与点类似,但是它在命名空间中使用:
let least = std::cmp::min(3, 8); // 这里是 3
use
指令可以用于将其他命名空间的名称 “引入作用域”:
use std::cmp::min;
let least = min(7, 1); // 这里是 1
在 use
指令中,大括号还有另外一层意思: 它想要同时导入 min
和 max
,我们可以使用任意一种:
// 这样可以
use std::cmp::min;
use std::cmp::max;
// 这样也行
use std::cmp::{min, max};
// 这样也没问题
use std::{cmp::min, cmp::max};
通配符 *
可以导入命名空间中的全部符号:
use std::cmp::*;
类型也是命名空间,方法可以像普通函数一样被调用:
let x= "amos".len(); // 4
let x= str::len("amos"); // 也是 4
str
是一个基本类型,但许多默认非基本类型也在作用域中:
// `Vec` 是一个常规结构体,不是基本类型
let v = Vec::new();
// 这是完全相同的代码,但使用了`Vec`的全路径
let v = std::vec::Vec::new();
这是有效的,因为 Rust 会在每个模块的开头插入它:
use std::prelude::v1::*;