Rust 基础语法和数据类型

news2024/12/28 20:14:08

数据类型

Rust提供了一系列的基本数据类型,包括整型(如i32u32)、浮点型(如f32f64)、布尔类型(bool)和字符类型(char)。此外,Rust还提供了原生数组、元组和可变数组(Vec)等复合数据类型。

基本数据类型

整型 (Integers)
let decimal: i32 = 42; // 有符号32位整数

let hex: u32 = 0x1A; // 无符号32位十六进制整数

let binary: u32 = 0b1100; // 无符号32位二进制整数
浮点型 (Floating-Point Numbers)
let float: f32 = 3.14; // 32位浮点数

let double: f64 = 3.141592653589793; // 64位浮点数
布尔类型 (Booleans)

布尔值 true 或 false 

let is_active: bool = true;
字符类型 (Characters)

字符类型,表示一个 Unicode 标量值 

let ch: char = 'a';

复合数据类型

原生数组 (Arrays)

固定长度的数组,所有元素类型必须相同 

let arr: [i32; 5] = [1, 2, 3, 4, 5];
元组 (Tuples)

元组类型,可以包含不同类型的元素

let tuple: (i32, char, f64) = (1, 'a', 3.14);
可变数组 (Vectors)

动态长度的数组,可以通过push等方法修改

let mut vec: Vec<i32> = Vec::new();

vec.push(10);
vec.push(20);
vec.push(30);

变量的可变性

Rust中的变量默认是不可变的。如果你想要一个可变的变量,你需要在声明时使用mut关键字。这有助于编译器在编译时期就确保程序的状态变化是可预测和一致的。

可变变量的声明和修改
fn main() {
    let mut number: i32 = 10; // 声明一个可变的整数变量 
    number += 5; // 修改变量的值
    println!("The number is now: {}", number);
}

在这个例子中,我们声明了一个名为number的可变整数变量,并将其值初始化为10。然后我们通过加法操作符+=修改了它的值。由于number是可变的,所以我们可以这样做。

在函数中修改可变参数
fn increment(number: &mut i32) {
    *number += 1;
}

fn main() {
    let mut value: i32 = 42;
    increment(&mut value);
    println!("The value is now: {}", value);
}

在这个例子中,我们定义了一个函数increment,它接受一个可变引用作为参数,并增加其指向的值。在main函数中,我们调用increment并传入value的可变引用。由于value是可变的,我们可以传递它的引用给函数,函数内部通过解引用来修改它的值。

使用mut来修改集合中的元素
fn main() {
    let mut list: Vec<i32> = vec![1, 2, 3, 4, 5];
    for item in &mut list {
        *item += 1;
    } 
    println!("The list after incrementing: {:?}", list);
}

在这个例子中,我们创建了一个可变的整数向量list,并初始化了一些值。然后我们遍历这个向量的可变引用,并逐一增加每个元素的值。由于我们在遍历时使用了&mut,我们可以在循环内部修改每个元素。

引用和借用

在Rust中,引用和借用是核心概念,它们允许你安全地操作数据而不拥有它的所有权。引用是指向某个值的指针,而借用则是一种特殊的引用,它遵循一定的生命周期规则。Rust的引用和借用机制允许你安全地共享和操作数据。引用是一个指针,指向另一个值而不拥有它,而借用则是在一定条件下对数据的临时访问。这些机制确保了数据的安全性和完整性。下面是一些关于引用和借用的例子:

引用

引用允许你访问数据而不获取其所有权。这意味着你可以读取或修改数据,但不会将其从原始位置移动或复制。

fn main() {
    let s = "Hello, world!";
    let s_ref = &s; // 创建一个对s的引用
    println!("The string is: {}", s_ref);
}

在这个例子中,s_ref是一个对s的引用。我们没有获取s的所有权,因此ss_ref创建后仍然有效。

可变引用

可变引用是对可变数据的引用,允许你修改数据的值。

fn main() {
    let mut s = String::from("Hello, world!");
    let s_mut = &mut s;
    s_mut.push_str(" in Rust!");
    println!("The modified string is: {}", s);
}

在这个例子中,s_mut是一个可变引用,它允许我们向s字符串中添加更多的文本。注意,s必须是可变的(String类型),因为只有可变变量才能有可变引用。

借用

借用是Rust中的一种机制,它确保你只能有一个可变引用或者任意数量的不可变引用。这是通过生命周期来实现的。

fn main() {
    let s = "Hello, world!";
    let result = longest_borrow(&s);
    println!("The result is: {}", result);
}

fn longest_borrow<'a>(_arg: &'a str) -> &'a str {
    _arg
}

在这个例子中,longest_borrow函数接受一个字符串的引用作为参数,并返回一个引用。函数的返回类型是&'a str,其中'a是生命周期。这意味着返回的引用的生命周期不会超过参数的生命周期。这样做可以防止数据竞争和悬挂引用,确保了内存安全。

借用规则

Rust的借用规则确保引用的有效性和安全性:

  1. 要么有多个不可变引用(但不允许可变引用),要么有一个可变引用(此时不允许其他任何引用)。
  2. 引用的生命周期不能超过被引用数据的生命周期。

这些规则在编译时由编译器强制执行,确保了代码的内存安全性。通过理解和使用引用和借用,你可以编写出既安全又高效的Rust代码。

控制语句

Rust提供了常见的控制结构:条件、循环、分支。

条件语句(if)

条件语句允许根据表达式的值来执行不同的代码块。

fn main() {
    let score = 85;

    if score >= 90 {
        println!("Grade: A");
    } else if score >= 80 {
        println!("Grade: B");
    } else if score >= 70 {
        println!("Grade: C");
    } else {
        println!("Grade: F");
    }
}

在这个例子中,根据 score 变量的值,程序会打印出相应的成绩等级。

循环(loop)

循环允许反复执行一段代码,直到满足某个条件。

fn main() {
    let mut count = 0;

    loop {
        count += 1;
        if count > 5 {
            break;
        }
        println!("Count: {}", count);
    }

    println!("Loop finished.");
}

在这个例子中,loop 会无限执行,直到 count 变量的值大于 5。break 语句用于退出循环。

for 循环

for 循环通常用于遍历集合中的元素。

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];

    for number in numbers.iter() {
        println!("Number: {}", number);
    }
}

在这个例子中,我们创建了一个整数向量 numbers,然后使用 for 循环遍历它的每个元素。

分支(match)

match 语句是一种多路选择结构,允许根据变量的值选择执行不同的代码块。

fn main() {
    let option = Some(4);

    match option {
        Some(0) => println!("Zero"),
        Some(1) => println!("One"),
        Some(2) ... Some(5) => println!("Two to five"),
        _ => println!("Something else"),
    }
}

在这个例子中,match 语句根据 option 变量的值来执行不同的代码块。这里使用了模式匹配和范围匹配。

这些控制流结构是 Rust 编程中的基础,它们使得编写逻辑清晰、结构良好的代码成为可能。通过合理使用这些结构,你可以构建出功能强大且易于维护的 Rust 程序。

函数

Rust的函数使用fn关键字来定义,并且可以返回值。根据其特性和用途被分为几个不同的类别。以下是一些主要的 Rust 函数分类以及相应的例子:

标准函数 (Standard Functions)

Rust 提供了一系列标准函数,这些函数可以直接使用,无需额外的导入或声明。

fn main() {
    let result = max(10, 20); // 使用标准函数max
    println!("The greater number is: {}", result);
}
用户定义函数 (User-Defined Functions)

用户可以定义自己的函数来执行特定的任务。

fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

fn main() {
    let message = greet("World");
    println!("{}", message);
}

在这个例子中,我们定义了一个 greet 函数,它接受一个字符串切片作为参数,并返回一个问候语的字符串。

关联函数 (Associated Functions)

关联函数与结构体相关联,但它们不是结构体的方法。它们通常用于操作与结构体相关的数据。

struct Point {
    x: f64,
    y: f64,
}

fn distance(p1: &Point, p2: &Point) -> f64 {
    ((p1.x - p2.x).powi(2) + (p1.y - p2.y).powi(2)).sqrt()
}

fn main() {
    let p1 = Point { x: 1.0, y: 2.0 };
    let p2 = Point { x: 4.0, y: 6.0 };
    let d = distance(&p1, &p2);
    println!("The distance is: {}", d);
}
方法 (Methods)

方法类似于关联函数,但它们是定义在结构体上的,可以通过实例调用。

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

fn main() {
    let rect = Rectangle { width: 30, height: 50 };
    let a = rect.area();
    println!("The area of the rectangle is: {}", a);
}

在这个例子中,我们定义了一个 Rectangle 结构体,并为其实现了 area 方法,用于计算矩形的面积。

闭包 (Closures)

闭包是一种匿名函数,可以捕获其环境的变量。

fn main() {
    let adder = |x: i32, y: i32| x + y;
    let result = adder(10, 20);
    println!("The result of adding is: {}", result);
}

在这个例子中,我们创建了一个闭包 adder,它接受两个 i32 类型的参数并返回它们的和。

函数指针 (Function Pointers)

Rust 允许将函数作为一等公民,这意味着你可以将函数作为参数传递给其他函数,或者将它们存储在变量中。

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

fn apply_operation(a: i32, b: i32, operation: fn(i32, i32) -> i32) -> i32 {
    operation(a, b)
}

fn main() {
    let result = apply_operation(10, 20, add);
    println!("The result of the operation is: {}", result);
}

在这个例子中,apply_operation 函数接受一个额外的参数 operation,它是一个函数指针,指向一个接受两个 i32 参数并返回一个 i32 的函数。

这些函数类别展示了 Rust 语言在函数定义和使用方面的灵活性和强大功能。通过合理地使用这些函数类型,你可以编写出高效、可读性强且易于维护的代码。

可以使用称被为宏的自定义句法形式来扩展 Rust 的功能和句法。宏需要被命名,并通过一致的句法去调用:some_extension!(...)。定义新宏有两种方式:

  • 声明宏(Macros by Example)以更高级别的声明性的方式定义了一套新句法规则。
  • 过程宏(Procedural Macros)可用于实现自定义派生。

Rust提供了很多标准宏,如: 

println! 宏 - 用于打印输出到控制台,是 Rust 中最常用的宏之一。
format! 宏 - 用于创建一个格式化的字符串,与 println! 类似,但是返回一个 String 类型的值。
vec! 宏 - 用于创建一个 Vec 类型的数组。

println!("Hello, world!");

let formatted_string = format!("The value is: {}", value);

let numbers = vec![1, 2, 3, 4, 5];

结构体和方法

Rust使用结构体(struct)来定义复合数据类型。结构体可以包含数据和方法(与面向对象编程中的成员函数类似)。Rust的方法使用impl关键字来定义,并且可以修改结构体的状态。

在Rust中,结构体是一种自定义的数据类型,它允许你将多个可能不同类型的值组合成一个单一的复合类型。结构体的每个字段称为属性,可以有不同的数据类型。除了定义数据结构,你还可以为结构体定义方法来指定其行为。方法在Rust中通过impl关键字实现,它们类似于面向对象编程中的成员函数。

结构体定义

下面是一个简单的结构体定义的例子:

struct Point {
    x: i32,
    y: i32,
}

这个Point结构体有两个属性:xy,它们都是i32类型。

方法定义

为结构体定义方法,你需要使用impl关键字,后面跟着结构体的名称。方法可以接受结构体的引用作为参数,并且可以有返回值。

impl Point {
    // 无参的关联函数
    fn new(x: i32, y: i32) -> Point {
        Point { x, y }
    }

    // 接收结构体的不可变引用,并返回一个值
    fn x(&self) -> i32 {
        self.x
    }

    // 接收结构体的可变引用,并修改其状态
    fn set_x(&mut self, value: i32) {
        self.x = value;
    }
}

在这个例子中,我们定义了三个方法:

  1. new - 一个关联函数,用于创建Point结构体的新实例。
  2. x - 一个实例方法,它返回Pointx属性的值。
  3. set_x - 一个实例方法,它接受一个i32类型的参数,并设置Pointx属性为这个值。
使用结构体和方法

创建Point结构体的实例并调用其方法:

fn main() {
    // 使用关联函数创建Point实例
    let point = Point::new(1, 2);

    // 调用实例方法获取x属性的值
    println!("Point x: {}", point.x());

    // 修改Point的x属性
    point.set_x(10);
    println!("Point x after set: {}", point.x());
}

在这个例子中,我们首先使用Point::new关联函数创建了一个Point实例。然后,我们调用了x方法来获取x属性的值,并打印出来。接着,我们调用了set_x方法来修改x属性的值,并再次打印出来。

通过这种方式,Rust的结构体和方法提供了一种强大的方式来定义和操作自定义数据类型。它们使得代码更加模块化,并且可以很容易地维护和扩展。

所有权系统

Rust的所有权系统是其核心特性之一,它允许语言在编译时期就避免数据竞争和空指针等问题。在Rust中,每个值都有一个变量作为其所有者。一个值在任意时刻只能有一个所有者,当所有者超出作用域,该值也会被自动清理。所有权可以通过变量赋值(move)或通过引用和借用来转移或共享。

特征(Traits)

Rust的特征(trait)是一种定义共享行为的方式。特征类似于接口,允许不同类型的数据实现相同的行为。特征还可以用于泛型编程,使得函数可以接受实现了特定特征的任何类型作为参数。

泛型

Rust支持泛型编程,允许定义可以操作多种类型数据的函数和结构体。泛型在Rust中通过类型参数和约束来实现,提供了强大的类型安全和灵活性。

总结

总的来说,Rust是一种现代的系统编程语言,它通过所有权、借用检查器和类型推断等机制,提供了一种安全、高效和灵活的编程方式。Rust的设计注重内存安全和并发,它提供了与C++相媲美的性能,同时避免了内存管理错误和数据竞争等问题。Rust的设计理念和特性使其成为了系统编程和并发编程的理想选择。

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

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

相关文章

记忆的方法 简单易行的记忆技巧:归纳整理,联想,重点标注压缩,改错,留痕记念(去个地方买个特别能长久保留的纪念品),差异

记忆的方法有很多&#xff0c;以下是一些简单易行的记忆技巧&#xff1a; 分类整理&#xff1a;将需要记忆的信息进行分类&#xff0c;这样可以帮助你更好地组织和记忆信息。例如&#xff0c;尝试记住一组词语时&#xff0c;可以将它们按照类别或相关性分组。归纳整理。间隔重…

mysql的安装和部署

##官网下载mysql 我下载的是一个mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz 可以通过xshell 或者xftp传送 xshell则是先下载一个lrzsz 执行以下的命令 yum install lrzsz -y #安装好我下面有个一键安装的脚本 #!/bin/bash#解决软件的依赖关系 yum install cmake ncurses…

LangChain学习笔记—RAG(检索增强生成)

LangChain LangChain是一个软件开发框架&#xff0c;可以更轻松地使用大型语言模型&#xff08;LLM&#xff09;创建应用程序。它是一个具有 Python 和 JavaScript 代码库的开源工具。LangChain 允许开发人员将 GPT-4 等 LLM 与外部数据相结合&#xff0c;为聊天机器人、代码理…

代理IP在爬虫中的连接复用与开销减少

目录 一、引言 二、代理IP的基本概念 三、代理IP在爬虫中的使用 四、代理IP的连接复用 五、减少开销的策略 六、代码示例与注释 七、总结 一、引言 在爬虫开发中&#xff0c;代理IP的使用是常见的做法&#xff0c;尤其在目标网站设置了反爬虫机制时。代理IP能够帮助爬虫…

【鸿蒙 HarmonyOS】获取设备的地理位置

一、背景 获取移动设备的地理位置&#xff0c;包含&#xff1a;经度、维度、具体地理位置等&#xff0c;地理位置信息能在许多业务场景中被应用&#xff0c;如导航、地图服务、位置服务、社交媒体等。 下面以一个Demo例子&#xff0c;来实现获取设备地理位置的功能 官方文档…

27.WEB渗透测试-数据传输与加解密(上)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;26.WEB渗透测试-BurpSuite&#xff08;五&#xff09; BP抓包网站网址&#xff1a;http:…

经济学 赋税

赋税&#xff1a; 1.为政府服务提供金钱来源 2. 用于保护环境 3.帮助国家使用财政和货币政策&#xff0c;推动经济增长 4.再分配社会财富的一种方式&#xff0c;平衡富人和穷人的贫富差距 5.帮助我们支付市场自身可能无法实现的服务&#xff0c;比如公共安全&#xff0c;国…

Day105:代码审计-PHP原生开发篇SQL注入数据库监控正则搜索文件定位静态分析

目录 代码审计-学前须知 Bluecms-CNVD-1Day-常规注入审计分析 emlog-CNVD-1Day-常规注入审计分析 emlog-CNVD-1Day-2次注入审计分析 知识点&#xff1a; 1、PHP审计-原生态开发-SQL注入&语句监控 2、PHP审计-原生态开发-SQL注入&正则搜索 3、PHP审计-原生态开发-SQ…

全力推进Copilot,微软抽调Teams团队精英

据 Business Insider 网站报道&#xff0c;他们获得的一份俺们微软内部备忘录显示&#xff0c;说俺们微软正在建立一个专门团队&#xff0c;负责俺们家的 Copilot 及其相关产品的后续开发工作。 该备忘录由俺们微软人工智能业务副总裁贾里德・斯帕塔罗&#xff08;Jared Spata…

【201】Java8读取JSON树形结构并插入到MySQL数据库表中

我写了一个 maven 项目的 Demo&#xff0c;用来演示 JAVA8 如何读取 JSON 文件树形结构&#xff0c;并将这种树形结构保存到 MySQL 中。 json文件 city.json {"name": "山东省","sub": [{"name": "青岛市","sub"…

【蓝桥杯嵌入式】RTC——实时时钟

一、RTC简介 RTC RTC—real time clock&#xff0c;实时时钟&#xff0c;主要包含日历、闹钟和自动唤醒这三部分的功能&#xff0c;其中的日历功能我们使用的最多。日历包含两个32bit的时间寄存器&#xff0c;可直接输出时分秒&#xff0c;星期、月、日、年。 从Cubemx里的配置…

【OpenCV】图像算术操作

1 前言 介绍图像算术操作&#xff0c;以及其可以实现的图像亮度、对比度调整效果。相关API&#xff1a; add() subtract() multiply() divide() addWeighted() 2 代码及内容 #include "iostream" #include "opencv2/opencv.hpp"using namespace std…

成都源聚达:抖音小店押金收费标准

在数字浪潮中&#xff0c;抖音小店如星辰般熠熠生辉&#xff0c;吸引了无数商家和创业者。然而&#xff0c;想要在这片星海中畅游&#xff0c;首先得了解其押金的收费标准。正如古人言&#xff1a;“无规矩不成方圆”&#xff0c;明确规则是成功的关键一步。 抖音小店的押金制度…

java爬虫入门程序

<!--爬虫仅支持1.8版本的jdk--> <!-- 爬虫需要的依赖--> <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.2</version> </dependency><!-- 爬虫需…

vue2+element-ui 实现OSS分片上传+取消上传

遇到问题&#xff1a;项目中需要上传500MB以上的视频。一开始使用上传组件el-upload&#xff0c;调用后台接口&#xff0c;但是出现了onprogress显示百分百后接口一直pending&#xff0c;过了很多秒后接口才通&#xff0c;如果遇到大文件的话&#xff0c;接口就会报超时。 解决…

批量复制空白文件夹,轻松管理文件,高效办公新选择

在繁忙的办公环境中&#xff0c;文件管理是提升工作效率的关键。想象一下&#xff0c;你需要为每一个新项目、新任务或新客户创建一个新的文件夹来整理和存储相关文件。手动一个一个地创建文件夹不仅耗时&#xff0c;而且容易出错。现在&#xff0c;我们为你带来一个全新的解决…

R语言中的常用数据结构

目录 R对象的基本类型 R对象的属性 R的数据结构 向量 矩阵 数组 列表 因子 缺失值NA 数据框 R的数据结构总结 R语言可以进行探索性数据分析&#xff0c;统计推断&#xff0c;回归分析&#xff0c;机器学习&#xff0c;数据产品开发 R对象的基本类型 R语言对象有五…

[leetcode] 25. K 个一组翻转链表

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值…

老板们注意了,AI可能在悄悄威胁你的工作

前天,科技新闻大佬The Register发了一篇文章,说的是AI在科研领域的管理角色越来越大,可能会让管理岗位变得过时,听起来是不是有点儿疯狂? ESMT Berlin的研究小伙伴们发现,AI能够以更大的规模和效率来管理研究项目,比如审查科学文献和预测创新化合物等等,而不是取代人类…

【Frida】【Android】 工具篇:ProxyPin抓包详解

&#x1f6eb; 系列文章导航 【Frida】【Android】01_手把手教你环境搭建 https://blog.csdn.net/kinghzking/article/details/136986950【Frida】【Android】02_JAVA层HOOK https://blog.csdn.net/kinghzking/article/details/137008446【Frida】【Android】03_RPC https://bl…