Rust 基本语法

变量

整数

  • 无符号整数以u开头
  • 有符号整数以i开头
  • 对于Rust默认整数是i32
  • 对于整数溢出
    • 开发模式中编译会检测溢出,如果溢出会导致程序panic
    • 发布模式中编译不会检查可能会导致的溢出,如果运行时发生溢出,会执行环绕操作保证数值在范围内且程序不会panic

单精度浮点类型

  • f32

双精度浮点类型

  • f64
  • Rust采用f64作为默认的浮点类型

布尔类型

  • bool:占用1字节大小

字符类型

  • char:占用4字节大小
  • 使用单引号

复合类型

  • 元组(Tuple):可以将多个类型的多个值放在一个类型里,长度固定一旦创建无法修改
    • 创建:在小括号中,将值用逗号分开
    • Tuple中的每一个位置都对应一个类型,Tuple中各元素的类型不必相同
    • 访问Tuple元素使用 .下标 进行访问
  • 数组:数组元素类型必须相同,数组长度固定,在栈上存储
    • 创建:在中括号中,将值用逗号分开
    let a:[i32; 5] = [1, 2, 3, 4, 5];
    let a = [3; 5];// 等于let a = [3, 3, 3, 3, 3];
    
    • 使用 [下标] 访问数组元素
    • 下标越界编译会通过,但是运行会panic

字符串

  • String在堆内存上分配,能够存储在编译时未知数量的文本
  • String类型的值可以修改,但是字符串字面值不能修改,因为字符串字面值在编译时就知道它的内容了,其文本内容直接被硬编码到最终的可执行文件里(速度快,高效,是因为它的不可变性),对于String类型,为了支持可变性,需要在堆内存上分配内存来保存编译时未知的文本内容(操作系统必须在运行时来请求内存,这步通过调用String::from来实现,当用完String后,需要使用某种方式将内存返回给操作系统)
let mut s = String::from("abcdefg");
s.push_str("hi");
// s -> abcdefghi
  • 一个String由三个部分组成(这部分存放在栈中,字符串内容存放在堆中)
    • 指向内容的指针
    • 长度(存放字符串内容所需的字节数)
    • 容量(从操作系统获得的总字节数)
let s1 = String::from("123");
let s2 = s1;
// s1将不能再被使用
let s1 = String::from("123");
let s2 = s1.clone();
// s1和s2独立

Copy trait

  • 如果一个类型实现了Copy这个trait,那么旧的变量在赋值后任然可以使用
  • 如果一个类型或者该类型的一部分实现了Drop trait,那么Rust不允许让它再去实现Copy trait了

一些拥有Copy trait的类型

  • 任何简单标量的组合类型都可以是Copy的
  • 任何需要分配内存或者某种资源的都不是Copy的
  • 一些拥有Copy trait的类型:
    • 所有的整数类型,例如u32
    • bool
    • char
    • 所有的浮点类型
    • Tuple(元组)要求其所有字段都是Copy的

函数

声明

使用 fn 关键字
Rust命名规范(snake case):

  • 针对函数和变量名,所有字母都是小写,单词之间使用下划线分开

参数

  • 在函数签名里,必须声明每个参数的类型

语句/表达式

  • 函数体由一系列语句组成,可选的由一个表达式结束
  • Rust是一个基于表达式的语言
  • 语句是执行一些动作的指令
  • 表达式会计算产生一个值
  • 函数的定义也是语句
  • 语句没有返回值,所以不可以使用let将一个语句赋给一个变量
// 块表达式
let y = {
    let x = 1;
    x + 3
}
// y等于块表达式最后一个值即x + 3 = 4
// 如果x + 3后加上分号,那么x + 3就变成语句了,分号后面没有返回值,默认就是空的Tuple即()
fn f() -> i32{
   5
}

fn main(){
   let res = f();// res为5
}

返回值

  • -> 符号后边声明函数返回值的类型,但是不可以为返回值命名
  • 在Rust里面,返回值就是函数体最后一个表达式的值
  • 若想提前返回,需使用 return 关键字,并指定一个值
  • 大多数函数都是默认使用最后一个表达式作为返回值

注释

  • 单行注释
// 这是单行注释
  • 多行注释
// 这是
// 多行注释

/**
 * 这是
 * 多行注释
**/

控制流

if表达式

  • if 表达式 的条件必须是bool类型,否则会报错(Rust不会自动类型转换)
if 3 < 5{
   // true
}else{
   // false
}
let a = if 1 < 3 { 1 } else { 6 };
// a = 1;

loop表达式

  • loop表达式里的代码会一直循环执行,直到break
let mut cnt = 0;
let res = loop{
    cnt += 1;
    if cnt == 10 {
        break cnt;
    }
}
// res = 10;

while循环

let mut cnt = 100;
while cnt > 0 {
    cnt -= 1;
}
// res = 0;

for循环

  • 安全,简洁,用得较多
let a = [1, 2, 3, 4];

for tem in a.iter() {
    println!("{}", tem);
}

Range

  • 标准库提供
  • 指定开始数字和结束数字,Range可以生成他们之间的数字(不含结束)
  • rev方法可以反转Range
// (1..4)生成1 - 3 之间的数字
// rev()反转,即 3 - 1之间的数字
// 输出 3 2 1
for tem in (1..4).rev() {
    println!("{}", tem);
}

所有权

  • Rust的核心特性就是所有权
  • 所有程序在运行时都必须管理它们使用计算机内存的方式
    • 有些语言有垃圾收集机制,在程序运行时,他们会不断地寻找不再使用的内存
    • 在其他语言中,程序员必须显示地分配和释放内存
  • Rust采用了第三种方式
    • 内存是通过一个所有权系统来管理的,其中包含一组编译器在编译时检查的规则
    • 当程序运行时,所有权特性不会减慢程序的运行速度

栈内存(Stack)/堆内存(Heap)

  • 栈内存
    • 后进先出
    • 所有存储在栈内存上的数据必须拥有已知的固定大小
      • 编译时大小未知的数据或运行时大小可能发送改变的数据必须放在堆内存上
  • 堆内存
    • 内存组织性差一些
      • 当把数据放入堆内存时,会请求一定数量的空间
      • 操作系统在堆内存里找到一块足够大空间,把他标记为在用,并返回一个指针,也就是这个空间的地址
      • 这个过程叫做在堆内存上进行内存分配,有时仅称为 分配
  • 把值压到栈内存上不叫分配
  • 因为指针是已知固定大小的,可以把指针存放在栈内存上
    • 但如果想要实际数据,必须使用指针来定位
  • 把数据压到栈内存上要比在堆内存上分配快得多
    • 因为操作系统不需要寻找用来存储新数据的空间,那个位置永远都在栈内存的顶端
    • 在堆内存上分配空间需要做更多的工作
      • 操作系统需要找到一个足够大的空间来存放数据,然后要做好记录方便下次分配
  • 访问堆内存中的数据要比访问栈内存中的数据慢,因为需要通过指针才能找到堆内存中的数据
    • 对于现代的处理器来说,由于缓存的缘故,如果指令在内存中跳转的次数越少,那么速度就越快

函数调用

  • 调用函数时,值被传入到函数(也包括指向堆内存的指针)。函数本地的变量被压到栈内存上。当函数结束后,这些值会从栈内存上弹出。

所有权存在的原因

  • 所有权解决的问题

    • 跟踪代码的哪些部分正在使用堆内存的哪些数据
    • 最小化堆内存上的重复数据量
    • 清理堆内存上未使用的数据以避免空间不足
  • 所有权规则

    • 每个值都有一个变量,这个变量是该值的所有者
    • 每个值同时只能有一个所有者
    • 当所有者超出作用域(scope)时,该值将被删除

返回值与作用域

  • 函数在返回值的过程中同样也会发生所有权的转移
  • 一个变量的所有权总是遵循同样的模式:
    • 把一个值赋值给其他变量时就发生移动
    • 当一个包含堆内存数据的变量离开作用域时,它的值就会被drop函数清理,除非数据的所有权移动到另一个变量上了

引用

  • &表示引用,允许你引用某些值而不取得其所有权

借用

  • 把引用作为函数参数这个行为叫做借用
  • 不可以修改借用的东西
  • 和变量一样,引用默认也是不可变的

可变引用

#![allow(warnings)]
use std::io;
use std::error::Error;
use std::boxed::Box;
use std::convert::TryInto;
use std::cmp::Ordering;
use std::cmp::min;
use std::cmp::max;

fn calculate_length(s: &mut String) -> usize {
    s.push_str(" LTPP");
    s.len()
}

fn main() -> Result<(), Box<dyn Error>> {
    let mut s1: String = String::from("SQS");
    println!("{} {}", s1, s1.len());
    let len: usize = calculate_length(&mut s1);
    println!("{} {}", s1, len);
    Ok(())
}

运行结果

SQS 3
SQS LTPP 8

  • 在特定作用域内,对于某一块数据,只能有一个可变的引用

    • 好处:在编译时解决数据竞争
  • 以下三种行为会发生数据竞争

    • 两个或多个指针同时访问一个数据
    • 至少有一个指针用于写数据
    • 没有使用任何机制来同步数据的访问
  • 可以通过创建新的作用域,来允许非同时的创建多个可变引用

#![allow(warnings)]
use std::io;
use std::error::Error;
use std::boxed::Box;
use std::convert::TryInto;
use std::cmp::Ordering;
use std::cmp::min;
use std::cmp::max;


fn main() -> Result<(), Box<dyn Error>> {
    let mut s1: String = String::from("SQS");
    {
        let s2: String = String::from("LTPP");
        // s2 离开当前作用域后被销毁
    }
    let s1_2 = &mut s1; // s1_2为SQS
    println!("{}", s1_2);
    let s2_2 = &mut s2; // 报错,s2在当前作用域不存在
    println!("{}", s1_2); 
    Ok(())
}

运行结果

编译出错!
error[E0425]: cannot find value `s2` in this scope
  --> /main.rs:19:21
   |
19 |     let s2_2 = &mut s2; // 报错,s2在当前作用域不存在
   |                     ^^ help: a local variable with a similar name exists: `s1`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0425`.
  • 不可同时拥有一个可变引用和一个不可变引用
  • 多个不可变的引用是可以的
#![allow(warnings)]
use std::io;
use std::error::Error;
use std::boxed::Box;
use std::convert::TryInto;
use std::cmp::Ordering;
use std::cmp::min;
use std::cmp::max;

fn main() -> Result<(), Box<dyn Error>> {
    let mut s: String = String::from("SQS");
    let r1 = &s;
    let r2 = &s;
    let s1 = &mut s;
    println!("{} {} {}", r1, r2, s1);
    Ok(())
}

运行结果

编译出错!
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
  --> /main.rs:14:14
   |
12 |     let r1 = &s;
   |              -- immutable borrow occurs here
13 |     let r2 = &s;
14 |     let s1 = &mut s;
   |              ^^^^^^ mutable borrow occurs here
15 |     println!("{} {} {}", r1, r2, s1);
   |                          -- immutable borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0502`.

悬空引用

  • 悬空指针:一个指针引用了内存中的某个地址,而这块内存可能已经释放并分配给其他人使用了
#![allow(warnings)]
use std::io;
use std::error::Error;
use std::boxed::Box;
use std::convert::TryInto;
use std::cmp::Ordering;
use std::cmp::min;
use std::cmp::max;

fn dangle() -> &String {
    let s: String = String::from("SQS");
    &s
}

fn main() -> Result<(), Box<dyn Error>> {
    let r = dangle();
    Ok(())
}

运行结果ust

编译出错!
error[E0106]: missing lifetime specifier
  --> /main.rs:10:16
   |
10 | fn dangle() -> &String {
   |                ^ expected named lifetime parameter
   |
   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
   |
10 | fn dangle() -> &'static String {
   |                 +++++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0106`.
  • Rust里,编译器可保证引用永远都不是悬空引用

    • 如果引用了某些数据,编译器保证在引用离开作用域之前数据不会离开作用域
  • 引用的规则,任意给定的时刻,只能满足以下情况之一

    • 一个可变的引用
    • 任意数量不可变的引用

推荐几款学习编程的免费平台

免费在线开发平台(https://docs.ltpp.vip/LTPP/

       探索编程世界的新天地,为学生和开发者精心打造的编程平台,现已盛大开启!这个平台汇集了近4000道精心设计的编程题目,覆盖了C、C++、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3以及C#等众多编程语言,为您的编程学习之旅提供了一个全面而丰富的实践环境。       
      在这里,您不仅可以查看自己的代码记录,还能轻松地在云端保存和运行代码,让编程变得更加便捷。平台还提供了私聊和群聊功能,让您可以与同行们无障碍交流,分享文件,共同进步。不仅如此,您还可以通过阅读文章、参与问答板块和在线商店,进一步拓展您的知识边界。
       为了提升您的编程技能,平台还设有每日一题、精选题单以及激动人心的编程竞赛,这些都是备考编程考试的绝佳资源。更令人兴奋的是,您还可以自定义系统UI,选择视频或图片作为背景,打造一个完全个性化的编码环境,让您的编程之旅既有趣又充满挑战。

免费公益服务器(https://docs.ltpp.vip/LTPP-SHARE/linux.html

       作为开发者或学生,您是否经常因为搭建和维护编程环境而感到头疼?现在,您不必再为此烦恼,因为一款全新的免费公共服务器已经为您解决了所有问题。这款服务器内置了多种编程语言的编程环境,并且配备了功能强大的在线版VS Code,让您可以随时随地在线编写代码,无需进行任何复杂的配置。
随时随地,云端编码
       无论您身在何处,只要有网络连接,就可以通过浏览器访问这款公共服务器,开始您的编程之旅。这种云端编码的便利性,让您的学习或开发工作不再受限于特定的设备或环境。
丰富的编程语言支持
       服务器支持包括C、C++、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3以及C#等在内的多种主流编程语言,满足不同开发者和学生的需求。无论您是初学者还是资深开发者,都能找到适合自己的编程环境。
在线版VS Code,高效开发
       内置的在线版VS Code提供了与本地VS Code相似的编辑体验,包括代码高亮、智能提示、代码调试等功能,让您即使在云端也能享受到高效的开发体验。
数据隐私和安全提醒
       虽然服务器是免费的,但为了保护您的数据隐私和安全,我们建议您不要上传任何敏感或重要的数据。这款服务器更适合用于学习和实验,而非存储重要信息。

免费公益MYSQL(https://docs.ltpp.vip/LTPP-SHARE/mysql.html

       作为一名开发者或学生,数据库环境的搭建和维护往往是一个复杂且耗时的过程。但不用担心,现在有一款免费的MySQL服务器,专为解决您的烦恼而设计,让数据库的使用变得简单而高效。
性能卓越,满足需求
       虽然它是免费的,但性能绝不打折。服务器提供了稳定且高效的数据库服务,能够满足大多数开发和学习场景的需求。
在线phpMyAdmin,管理更便捷
       内置的在线phpMyAdmin管理面板,提供了一个直观且功能强大的用户界面,让您可以轻松地查看、编辑和管理数据库。
数据隐私提醒,安全第一
       正如您所知,这是一项公共资源,因此我们强烈建议不要上传任何敏感或重要的数据。请将此服务器仅用于学习和实验目的,以确保您的数据安全。

免费在线WEB代码编辑器(https://docs.ltpp.vip/LTPP-WEB-IDE/

       无论你是开发者还是学生,编程环境的搭建和管理可能会占用你宝贵的时间和精力。现在,有一款强大的免费在线代码编辑器,支持多种编程语言,让您可以随时随地编写和运行代码,提升编程效率,专注于创意和开发。
多语言支持,无缝切换
       这款在线代码编辑器支持包括C、C++、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3以及C#在内的多种编程语言,无论您的项目需要哪种语言,都能在这里找到支持。
在线运行,快速定位问题
       您可以在编写代码的同时,即时运行并查看结果,快速定位并解决问题,提高开发效率。
代码高亮与智能提示
       编辑器提供代码高亮和智能提示功能,帮助您更快地编写代码,减少错误,提升编码质量。

免费二维码生成器(https://docs.ltpp.vip/LTPP-QRCODE/

       二维码(QR Code)是一种二维条码,能够存储更多信息,并且可以通过智能手机等设备快速扫描识别。它广泛应用于各种场景,如:
企业宣传
       企业可以通过二维码分享公司网站、产品信息、服务介绍等。
活动推广
       活动组织者可以创建二维码,参与者扫描后可以直接访问活动详情、报名链接或获取电子门票。
个人信息分享
       个人可以生成包含联系方式、社交媒体链接、个人简历等信息的二维码。
电子商务
       商家使用二维码进行商品追踪、促销活动、在线支付等。
教育
       教师可以创建二维码,学生扫描后可以直接访问学习资料或在线课程。
交通出行
       二维码用于公共交通的票务系统,乘客扫描二维码即可进出站或支付车费。        功能强大的二维码生成器通常具备用户界面友好,操作简单,即使是初学者也能快速上手和生成的二维码可以在各种设备和操作系统上扫描识别的特点。

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WA-自动机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值