Skip to content

半小时学习 Rust

原文地址

A half-hour to learn Rust (fasterthanli.me)

谷歌翻译

在线阅读


  • [x] Item 1
    • [x] Item 1.1
  • [x] Item 2 为了提高编程语言的流利程度,我们必须大量阅读编程语言。但是,如果你不知道它的意思,又怎么能大量阅读呢?

在本文中,我不会只关注一两个概念,而是会尽可能多地介绍 Rust 片段,并解释其中包含的关键字和符号的含义。

准备好了吗?走起!

let 引入一个变量绑定:

rust
let x;	// 声明 "x"
x = 42;	// 将 42 赋值给 "x"

这也可以写成一行:

rust
let x = 42;

你可以通过:明确变量类型,一个类型声明:

rust
let x: i32;	// `i32` 是带符号的 32 位整数
x = 42;

// 这里有 i8, i16, i32, i64, i128
// 还有无符号的 u8, u16, u32, u64, u128

这也可以写成一行:

rust
let x: i32 = 42;

如果您声明了一个名称并在稍后将其初始化,编译器将阻止您在初始化之前使用它。

rust
let x;
x = 42;
foobar(x);	// 这里将推断出 `x` 的类型

下划线 _ 是一个特殊的名称,或者说,是一个 "无名 "的名称。它的基本意思是扔掉某些东西:

rust
// 因为 42 是一个常量,所以这样做没有*作用
let _ = 42;

// 这将调用 `get_thing` 但会丢弃其结果
let _ = get_thine();

以下划线开头的名称都是常规名称,只是编译器不会警告它们未被使用:

rust
// 我们最终可能会使用 `_x`,但我们的代码还在编写中。
// 我们只是想暂时消除编译器的警告。
let _x = 42;

可以引入具有相同名称的单独绑定 - 您可以隐藏变量绑定:

rust
let x = 13;
let x = x + 3;
// 在该行之后使用 `x` 仅引用第二个 `x`
// 第一个 `x` 已经不存在了

Rust 有元组,您可以将其视为 "不同类型值的固定长度集合"。

rust
let pair = ('a', 17);
pair.0;	// 这里是 'a'
pair.1; // 这里是 17

如果我们真的想注释配对的类型,我们可以这样写:

rust
let pair: (char, i32) = ('a', 17);

在执行任务时,可以对元组进行去结构化处理(解构),即把它们分解成各自的字段:

rust
let (some_char, some_int) = ('a', 17);
// 现在, `some_char` 是 'a',`some_int` 是 17

当一个函数返回一个元祖时是非常有用的:

rust
let (left, right) = slice.split_at(middle);

当然,当解构一个元祖时, _ 可以用作丢弃一部分:

rust
let (_, right) = slice.split_at(middle);

分号;标记语句的结束:

rust
let x = 3;
let y = 5;
let z = y + x;

这就意味着语句可以跨越多行:

rust
let x = vec![1, 2, 3, 4, 5, 6, 7, 8]
    .iter()
    .map(|x| x + 3)
    .fold(0, |x, y| x + y);

(我们稍后会讨论它们的实际含义)。

fn 声明一个函数

这里是一个没有返回值的函数:

rust
fn greet() {
	println!("Hi there!");
}

下面是一个返回 32 位有符号整数的函数。箭头->表示他的返回类型:

rust
fn pair_dice_roll() -> i32 {
	4
}

一对括号声明一个块,它有自己的作用域:

rust
// 先打印 "in",然后 "out"
fn main() {
	let x = "out";
	{
		// 这里是一个不同的 `x`
		let x = "in";
		println!("{}", x);
	}
	println!("{}", x);
}

块也是表达式, 意味着结果是一个值

rust
let x = 42;
let x = { 42 };

在一个块内, 可以有多行语句:

rust
let x = {
	let y = 1;
	let z = 2;
	y + z	// 尾行, 整个块的结果赋值给了 `x`
};

这就是为什么 "省略函数结尾的分号 "等同于返回,即它们是等价的:

rust
fn pair_dice_roll() -> i32 {
	return 4;
}

fn pair_dice_roll() -> i32 {
	4
}

if 条件也是表达式:

rust
fn pair_dice_roll() -> i32 {
	if feeling_lucky {
		6
	} else {
		4
	}
}

match 也是表达式:

rust
fn pair_dice_roll() -> i32 {
	match feeling_lucky {
		true => 6,
		false => 4,
	}
}

. 点通常用来访问字段值

rust
let a = (10, 20);
a.0; // 10

let amos = get_come_struct();
amos.nickname; // "fasterthanlime"

或者访问一个值的方法:

rust
let nick = "fasterthanlime";
nick.len();	// nick 的长度 14

两个冒号 ::,与点类似,但是它在命名空间中使用:

rust
let least = std::cmp::min(3, 8); // 这里是 3

use 指令可以用于将其他命名空间的名称 “引入作用域”:

rust
use std::cmp::min;

let least = min(7, 1); // 这里是 1

use 指令中,大括号还有另外一层意思: 它想要同时导入 minmax,我们可以使用任意一种:

rust
// 这样可以
use std::cmp::min;
use std::cmp::max;

// 这样也行
use std::cmp::{min, max};

// 这样也没问题
use std::{cmp::min, cmp::max};

通配符 * 可以导入命名空间中的全部符号:

rust
use std::cmp::*;

类型也是命名空间,方法可以像普通函数一样被调用:

rust
let x= "amos".len();	// 4
let x= str::len("amos"); // 也是 4

str 是一个基本类型,但许多默认非基本类型也在作用域中:

rust
// `Vec` 是一个常规结构体,不是基本类型
let v = Vec::new();

// 这是完全相同的代码,但使用了`Vec`的全路径
let v = std::vec::Vec::new();

这是有效的,因为 Rust 会在每个模块的开头插入它:

rust
use std::prelude::v1::*;