半小时入门Rust,这是一篇Rust代码风暴
Rust 是一门系统编程语言,专注于安全,尤其是并发安全。它支持函数式和命令式以及泛型等编程范式的多范式语言,且 TensorFlow 等深度学习框架也把它作为一个优秀的前端语言。
Rust 在语法上和 C、C++类似,都由花括弧限定代码块,并有相同的控制流关键字,但 Rust 设计者想要在保证性能的同时提供更好的内存安全。Rust 自 2016 年就已经开源了,在各种开发者调查中,它也总能获得「最受欢迎的语言」这一称赞,目前该开源项目已有 42.9K 的 Star 量。
机器之心的读者大多数都非常熟悉 Python,而 Rust 就没那么熟悉了。在 Amos 最近的一篇博文中,他表示如果阅读他的作品,我们半个小时就能入门 Rust。因此在这篇文章中,我们将介绍该博文的主要内容,它并不关注于 1 个或几个关键概念,相反它希望通过代码块纵览 Rust 的各种特性,包括各种关键词与符号的意义。
在 HackNews 上,很多开发者表示这一份入门教程非常实用,Rust 的入门门槛本来就比较高,如果再介绍各种复杂的概念与特性,很容易出现「从入门到劝退」。因此这种从实例代码出发的教程,非常有意义。
从变量说起
let 能绑定变量:
let x; // declare "x"x = 42; // assign 42 to "x"let x = 42; // combined in one line
可以使用 :来制定变量的数据类型,以及数据类型注释:
let x: i32; // `i32` is a signed 32-bit integerx = 42;// there's i8, i16, i32, i64, i128// also u8, u16, u32, u64, u128 for unsignedlet x: i32 = 42; // combined in one line
如果你声明一个变量并在初始化之前就调用它,编译器会报错:
let x;foobar(x); // error: borrow of possibly-uninitialized variable: `x`x = 42;
然而,这样做完全没问题:
let x;x = 42;foobar(x); // the type of `x` will be inferred from here
下划线表示特殊的命名,或者更确切地说是「缺失的命名」,它和 Python 的用法有点像:
// this does *nothing* because 42 is a constantlet _ = 42;// this calls `get_thing` but throws away its resultlet _ = get_thing();
以下划线开头的命名是常规命名,只是编译器不会警告它们未被使用:
// we may use `_x` eventually, but our code is a work-in-progress// and we just wanted to get rid of a compiler warning for now.let _x = 42;
相同命名的单独绑定是可行的,第一次绑定的变量会取消:
let x = 13;let x = x + 3;// using `x` after that line only refers to the second `x`,// the first `x` no longer exists.
Rust 有元组类型,可以将其看作是「不同数据类型值的定长集合」。
let pair = ('a', 17);pair.0; // this is 'a'pair.1; // this is 17
如果真的想配置 pair 的数据类型,可以这么写:
let pair: (char, i32) = ('a', 17);
元组在赋值时可以被拆解,这意味着它们被分解成各个字段:
let (some_char, some_int) = ('a', 17);// now, `some_char` is 'a', and `some_int` is 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 fair_dice_roll() -> i32 { 4}
花括号表示了一个代码块,且拥有其自己的作用域:
// This prints "in", then "out"fn main() { let x = "out"; { // this is a different `x` let x = "in"; println!(x); } println!(x);}
代码块也是表示式,表示其计算为一个值。
// this:let x = 42;// is equivalent to this:let x = { 42 };
在一个代码块中,可以有多个语句:
let x = { let y = 1; // first statement let z = 2; // second statement y + z // this is the *tail* - what the whole block will evaluate to};
这也是为什么「省略函数末尾的分号」等同于加上了 Retrun,这些都是等价的:
fn fair_dice_roll() -> i32 { return 4;}fn fair_dice_roll() -> i32 { 4}
if 条件语句也是表达式:
fn fair_dice_roll() -> i32 { if feeling_lucky { 6 } else { 4 }}
match 匹配器也是一个表达式:
fn fair_dice_roll() -> i32 { match feeling_lucky { true => 6, false => 4, }}
Dots 通常用于访问某个对象的字段:
let a = (10, 20);a.0; // this is 10let amos = get_some_struct();amos.nickname; // this is "fasterthanlime"
或者调用对象的方法:
let nick = "fasterthanlime";nick.len(); // this is 14
双冒号与此类似,但可对命名空间进行操作。在此举例中,std 是一个 crate (~ a library),cmp 是一个 module(~ a source file),以及 min 是个函数:
let least = std::cmp::min(3, 8); // this is 3
use 指令可用于从其他命名空间中「引入范围」命名:
use std::cmp::min;let least = min(7, 1); // this is 1
在 use 指令中,花括号还有另一个含义:「globs」,因此可以同时导入 min 以及 max:
// this works:use std::cmp::min;use std::cmp::max;// this also works:use std::cmp::{min, max};// this also works!use std::{cmp::min, cmp::max};
通配符(*)允许从命名空间导入符号:
// this brings `min` and `max` in scope, and many other thingsuse std::cmp::*;
Types 也是命名空间和方法,它可以作为常规函数调用:
let x = "amos".len(); // this is 4let x = str::len("amos"); // this is also 4
str 是一个基元数据类型,但在默认情况下,许多非基元数据类型也在作用域中。
// `Vec` is a regular struct, not a primitive typelet v = Vec::new();// this is exactly the same code, but with the *full* path to `Vec`let v = std::vec::Vec::new()
至于为什么可行,因为 Rust 在每个模块的开头都插入了:
use std::prelude::v1::*;
相关文章
- git help 查看命令手册
- 【6】python生成数据曲线平滑处理——(Savitzky-Golay 滤波器、convolve滑动平均滤波)方法介绍,推荐玩强化学习的小伙伴收藏
- 数据挖掘机器学习[四]---汽车交易价格预测详细版本{嵌入式特征选择(XGBoots,LightGBM),模型调参(贪心、网格、贝叶斯调参)}
- 像go 一样 打造.NET 单文件应用程序的编译器项目bflat 发布 7.0版本
- 解决idea登录github出现的invalid authentication data 404 not found以及登录 token 失效
- 虹科方案|将以太网连接添加到Dell EMC PowerVault™ ML3 SAS库
- Linux运维常用shell脚本之系统管理实例
- Linux运维常用shell脚本之网络管理实例
- Java线程与Linux内核线程的映射关系
- PowerDesigner连接mysql逆向生成pdm
- oracle学习笔记(十六) PL/SQL 异常和goto语句
- gitlab使用培训
- 【完全开源】知乎日报UWP版(下篇):商店APP、github源码、功能说明。Windows APP 良心出品。
- The Similarities and Differences Between C# and Java -- Part 1(译)
- Django Admin实现三级联动(省市区)
- Linux运维工程师工作手册
- Linux系统初始化
- Linux三剑客之awk命令详解及相关实例
- linux的rsync工具的常用选项及ssh同步介绍
- Linux运维常用shell脚本实例