Rust学习笔记之基础概念快速入门

本文介绍了Rust编程语言的基础概念,包括Rust的历史、安装过程、Hello World示例、内置类型、变量定义、函数与闭包、字符串处理、条件分支和循环。还探讨了用户自定义类型如struct和enum,以及impl实现。通过这篇文章,读者可以对Rust有初步的认识。
摘要由CSDN通过智能技术生成

去年就学习过一段时间的Rust,除了略微“诡异”的所有权规则,整个语言的工具链体验还是很好的,起码Cargo真的很舒服。

聊聊Rust

Rust is technology from the past came to save the future from itself.
——Graydon Hoare

Rust 和 C++ 是同一系列的,经常被拿来一同比较的 Go 其实对标不是 C++,而是 Python 与 Java。我对 Rust 的看法就是没有历史包袱,现代化的 C++,由于 go 设计有 gc (垃圾回收),因此 go 可以说是一个更接地气的 Python 或者 Java。

Rust 的历史可以追溯到 2006 年,由 Graydon Hoare 开发,目前主要由 Mozilla 主导。第一个稳定版本 1.0 是在2015年发布的。据说,1.0 之前的那些版本,各种特性很容易在下一个版本就得不到兼容,1.0 之后才改变了这种轻易翻盘的情况,各种特性开始开始稳定下来。

Mozilla 主导 Rust 主要寄希望能解决 C++ 的内存安全问题,因为火狐浏览器的引擎 gecko 就是用 C++ 编写的。C++ 年代久远,对并发的支持也没有提供更好抽象,非常容易误用,这也是 Rust 试图解决的问题之一。

Rust 借鉴了很多语言,比如Cyclone(一种安全的C语言方言)的基于区域的内存管理模型;C++ 的RAII 原理;Haskell 的类型系统、错误处理类型、typeclasses等等。Rust 有非常小的 runtime,不需要垃圾回收,默认情况下是在栈上进行分类内存,而不是堆上。Rust 的编译器 rustc,一开始使用 Ocaml (一种函数式语言)编写,后来在2011年 Rust 实现了自举。

安装、更新和卸载

在Mac和Linux上安装相对而言会简单很多,只需要在终端输入以下命令:

curl https://sh.rustup.rs -sSf | sh

会自动配置好环境变量,重启一下终端,或者输入:

source $HOME/.cargo/env

更新的命令:

rustup update

卸载

rustup self uninstall

检验是否成功安装

rustc --version

Hello World

为了体现出 Rust 的特性,写一个稍微富含 Rust 风格的 Hello World。

// great.rs
use std::env;

fn main() {
   
  let name = env::args().skip(1).next();
  match name {
   
    Some(n) => println!("Hello, {}", n),
    None => panic!("Did not receive any name?"),
  }
}

现在使用 rustc 编译项目,并运行一下:

➜ rust_projects rustc greet.rs
➜ rust_projects ./greet Guyu2019
Hello, Guyu2019
➜ rust_projects ./greet         
thread 'main' panicked at 'Did not receive any name?', greet.rs:8:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

第二行,从 std Crate(库被称为 Crate) 中引入了 env 模块。第 4 行就是大家熟悉的 main 程序入口。

第一个命令行参数(下标为0),是程序本身的名字。第2个参数(下标为1)才是第一个输入参数。skip(1) 的意思就是跳过一个元素,它返回一个迭代器。由于迭代器是懒加载的逻辑,没有进行预计算,所以需要显式使用 next() 去获取元素。

next() 返回的也不是单纯的字符串,而是一个 Option 类型。Option 类型避免使用 null,用 None 来表示没有值。

第六行的 match 类似我们熟悉的 if ,也比较像 switch。如果返回 next() 返回了值,则调用 println!()。如果没有值,则到 Nonepanic!。最后的 ! 表明这是一个宏(macro),而不是我们通常理解的函数。

println! 宏接受一个字符串,还可以带有占位的 {} 语法。我们通常称这种字符串为格式化字符串(fotmat strings)。如果只是替换成原始的内置简单类型,可以使用 {},其它的类型通常会使用 {:?}

{} 的行为主要来自 Display trait,{:?} 则来自于 Debug trait。顾名思义,{} 最主要的功能是显示,{:?} 则多了调试的含义。对于内置的简单类型,Debug 显得就不那么重要了。如果是自己定义的类型,或者比较复杂的类型,可以使用 #[derive(Debug)] 去定义调试的行为,当然这是后话。

内置的原始类型

Rust 内建的原始类型有这些:

  • bool:布尔值,truefalse
  • char:单个字符
  • 整数类型:有一点特殊,Rust 可以支持 128 bit 的整数
长度 有符号 无符号
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
128-bit i128 u128
arch isize usize

其中,isizeusize依赖运行程序的计算机架构:64位的机器上是64位(等价与i64),32位上是32位(等价于i32),一般可以用来表示指针。如果拿不定主意,默认的i32就很好,通常是最快的。

  • f32:基于IEEE 754标准的32位的浮点数类型;
  • f64:64位浮点数类型;
  • [T; N]:固定长度的数组;
  • [T]:可变尺寸的 T 类型数组(类似 C++ 的vector);
  • str:字符串切片,主要用于引用,比如&str
  • (T, U, ..):无穷序列,TU 可以是不同的类型;
  • f(i32) -> i32:函数类型。函数在 Rust 中也是一等公民,函数可以像变量一样使用。这里仅仅只是举例,f(i32) -> i32 表示这个函数接受一个 i32 类型的值,然后函数返回 i32,函数类型根据函数参数和返回值发生变化。

定义变量

Rust中使用 let 进行定义变量。和C或者C++不同,变量默认是不可变的。这个主要是为了并发和所有权上进行考虑的。你可以理解成 let 就是 C++ 里的 const。如果要声明可变的变量,应该在变量名前面加上mut

// variables.rs

fn main() {
   
  let target = "world";
  let mut greeting = "Hello";
  println!("{}, {}", greeting, target);
  greeting = "How are you doing";
  target = "mate";
  println!("{}, {}", greeting, target);
}

编译运行这段代码,会发现报错了。编译器告诉你,target 不能改,要改请加上 mut。嗯,非常友好。
“变量”不变

函数与闭包

函数类型没什么大的意外。不过这里提一句,编写函数尽量编写纯函数,有的语言管纯函数叫函数,其它的叫方法。**纯函数的意思简单来讲就是不修改全局变量,函数内部需要的外部资源从参数中获取,然后不要直接修改外部资源,而是返回给外部。**这样的函数有明显的高内聚,低耦合的特点,比较容易进行调试和并行。

// functions.rs

fn add(a: u64, b: u64) -> u64 {
   
  a + b
}

fn main() {
   
  let a: u64 = 17;
  let b = 3;

  let result = add(a, b);
  println!("Result {}", result);
}

// Result 20

没有什么意外,和 C++ 有点差别的是,最后会自动返回最后 a + b 的结果,不需要加上 return。而且,Rust 的函数借鉴于函数式编程,就算没有返回值,也会默认返回 () 类型,可以把它当作 void

// function_mut.rs

fn increate_by(mut val: u32, how_much: u32) {
  val += how_much;
  println!("You made {} points", val);
}

fn main() {
  let score = 2048;
  increate_by(score, 30);

  println!("{}", score);
}
// You made 2078 points
// 2048

闭包相比与函数拥有环境的信息,它可以没有名字,所以有时候也被叫做匿名函数。最简单的闭包形式是这样的:

let my_closure = || ();

这样就定义了一个没有参数,然后什么也没干的函数。可以使用 my_closure() 去调用,这点上和函数没什么差别。

// closures.rs

fn main()
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值