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为SQSprintln!("{}", 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 errorFor 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 hereerror: aborting due to previous errorFor 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 errorFor more information about this error, try `rustc --explain E0106`.
  • Rust里,编译器可保证引用永远都不是悬空引用

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/20603.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spark大数据 掌握RDD的创建

在Apache Spark中&#xff0c;弹性分布式数据集&#xff08;Resilient Distributed Dataset&#xff0c;简称RDD&#xff09;是一个核心的数据结构&#xff0c;用于表示不可变、可分区、可并行操作的元素集合。理解并掌握RDD的创建是使用Spark进行大数据处理的关键步骤之一。 …

Qt Creator(Qt 6.6)拷贝一行

Edit - Preference - Environment&#xff1a; 可看到&#xff0c;拷贝一行的快捷键是&#xff1a; ctrl Ins

数据结构-堆(带图)详解

前言 本篇博客我们来仔细说一下二叉树顺序存储的堆的结构&#xff0c;我们来看看堆到底如何实现&#xff0c;以及所谓的堆排序到底是什么 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;数据结构_普通young man的博客-CSDN博客 若有问题 评…

程序员是牛马吗?

在今天的讨论中&#xff0c;一个引人深思的问题被提出&#xff1a;程序员是否只是现代社会的牛马&#xff1f;这个问题迅速引发了激烈的争论。许多程序员开始意识到&#xff0c;尽管他们辛勤工作&#xff0c;但最终可能仍无法摆脱被剥削的命运。因此&#xff0c;他们渴望改变&a…

MySQL(二)-基础操作

一、约束 有时候&#xff0c;数据库中数据是有约束的&#xff0c;比如 性别列&#xff0c;你不能填一些奇奇怪怪的数据~ 如果靠人为的来对数据进行检索约束的话&#xff0c;肯定是不行的&#xff0c;人肯定会犯错~因此就需要让计算机对插入的数据进行约束要求&#xff01; 约…

混合模型方差分析

文章目录 一、说明二、受试者“间”因素和受试者“内”因素的意思&#xff1f;三、混合模型方差分析回答 3 件事四、混合模型方差分析的假设 一、说明 在本文中&#xff0c;我将讨论一种称为混合模型方差分析的方差分析变体&#xff0c;也称为具有重复测量的 2 因素方差分析。…

音视频开发_SDL事件处理

今天我为大家介绍一下SDL的事件处理。这里所指的事件处理就是我们通常所说的&#xff0c;键盘事件&#xff0c;鼠标事件&#xff0c;窗口事件等。 SDL对这些事件都做了封装&#xff0c;提供了统一的API&#xff0c;下面我们就来详细的看一下。 SDL中的事件处理 要想了解 SDL…

VB.net进行CAD二次开发(四)

netload不能弹出对话框&#xff0c;参考文献2 参考文献1说明了自定义菜单的问题&#xff0c;用的是cad的系统命令 只要加载了dll&#xff0c;自定义的命令与cad的命令同等地位。 这时&#xff0c;可以将自定义菜单的系统命令替换为自定义命令。 <CommandMethod("Add…

STL-queue的使用及其模拟实现

在C标准库中&#xff0c;队列(queue)是一种容器适配器&#xff0c;它以先进先出的方式组织数据&#xff0c;其中从容器一端插入元素&#xff0c;另一端取出元素。 queue的使用 queue的构造函数 queue的成员函数 empty&#xff1a;检测队列是否为空size&#xff1a;返回队列中有…

代码随想录算法训练营 day23| ● 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树

文章目录 前言669. 修剪二叉搜索树思路方法一 递归法方法二 迭代法 108.将有序数组转换为二叉搜索树思路方法一 递归法方法二 迭代法 538.把二叉搜索树转换为累加树思路方法一方法二 总结 前言 迭代法都没看主要是669和538【538很简单】 669. 修剪二叉搜索树 思路 不用看教程…

【C++刷题】优选算法——位运算

常见位运算操作总结&#xff1a; 基础位运算 &&#xff1a;有0则为0 |&#xff1a;有1则为1 ^&#xff1a;相同为0&#xff0c;相异为1 / 无进位相加运算符的优先级 管它什么优先级&#xff0c;加括号就完事儿了给一个数 n&#xff0c;确定它的二进制表示中的第 i (默认是从…

【基本数据结构】平衡二叉树

文章目录 前言平衡二叉树1 简介2 旋转2.1 左旋2.2 右旋2.3 何时旋转 3 插入节点4 删除节点5 代码 参考资料写在最后 前言 本系列专注更新基本数据结构&#xff0c;现有以下文章&#xff1a; 【算法与数据结构】数组. 【算法与数据结构】链表. 【算法与数据结构】哈希表. 【…

【斯坦福因果推断课程全集】1_随机对照试验1

目录 The average treatment effect Difference-in-means estimation IID Sampling and Population Asymptotics Example: The linear model Regression adjustments with a linear model 随机对照试验&#xff08;RCT&#xff09;是统计因果推论的基础。如果有的话&#…

关于FPGA 使用SPI FLASH固化时如何配置固化参数

关于FPGA 使用SPI FLASH固化时如何配置固化参数 EDA工具&#xff1a;Vivado 关于FPGA 使用SPI FLASH固化时如何配置固化参数一、引言二、如何设置固化参数&#xff1a;使用50M的速度 &#xff0c;SPI为X4 &#xff0c;以及bit压缩第一&#xff1a;点open implenment design第二…

Android之onMeasure的三种模式

Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}在 Android 中&#xff0c;onMeasure() 方法是 View 或 ViewGroup 中的一个重要方法&#xff0c;用于测量视图的大小。在 onMeasure(…

安装软件缺少dll文件怎么办,分享多种解决dll问题的方法

在计算机使用过程中&#xff0c;我们经常会遇到安装软件时提示缺少dll文件的问题。这种情况通常会导致软件无法正常运行或启动。为了解决这个问题&#xff0c;我总结了以下五种方法&#xff0c;希望对大家有所帮助。 一&#xff0c;了解DLL文件是什么 动态链接库&#xff08;D…

简单说说我对集成学习算法的一点理解

概要 集成学习&#xff08;Ensemble Learning&#xff09;是一种机器学习技术框架&#xff0c;它通过构建并结合多个学习器&#xff08;也称为个体学习器或基学习器&#xff09;来完成学习任务。 集成学习旨在通过组合多个基学习器的预测结果来提高整体模型的性能。每个基学习…

常见仪表盘指示灯的含义,这次够全了!

汽车是当前主要的交通工具之一&#xff0c;给人们的工作、生活提供了便利。大家在学会开车的同时&#xff0c;也得了解一些基本的汽车常识&#xff0c;可以及时的发现车辆的问题&#xff0c;并作出正确的判断&#xff0c;以此降低车辆的损耗和维修成本。其中最基本的&#xff0…

房产证上加名?手把手教你操作,省钱又省心!

随着《民法典》的实施&#xff0c;房产的权属问题愈发受到重视。夫妻双方及其亲属常希望能在房产证上增添自己的名字&#xff0c;以保障各自的权益。那么&#xff0c;房产证上到底能写几个名字呢&#xff1f;以下是对这一问题的详细解答。 一、房产证命名无固定限制 在购房时&…

准确-K8s系列文章-修改containerd 默认数据目录

修改 Kubernetes 集群中 containerd 默认数据目录为 /data/containerd 前言 本文档适用于 Kubernetes 1.24 及以上版本的集群,介绍如何将 containerd 默认的数据目录从 /var/lib/containerd 修改为 /data/containerd。 步骤 1. 停止 containerd 服务(慎重!!!需评估风险!…