Rust 中 *、&、mut、&mut、ref、ref mut 的用法和区别

Rust 中,*refmut&ref mut 是用于处理引用、解引用和可变性的关键字和操作符,它们在不同的上下文中有不同的用法。

一、* 解引用

* 属于操作符

1. 作用

用于解引用指针或引用,以访问其指向的值。

通过解引用,可以从指针或引用中获取实际的值。

2. 用法

2.1. 解引用不可变引用

fn main() {
let x = 5;
let y = &x; // y 是对 x 的不可变引用
println!("y: {}", *y); // 通过解引用 y 获取 x 的值,输出: y: 5
}

2.2. 解引用可变引用

fn main() {
let mut x = 10;
let y = &mut x; // y 是对 x 的可变引用
*y += 5; // 通过解引用 y 修改 x 的值
println!("x: {}", x); // 输出: x: 15
}

2.3. 解引用指针

fn main() {
let x = 42;
let y = &x as *const i32; // 创建不可变裸指针
unsafe {
println!("y: {}", *y); // 解引用不可变裸指针
} let x = Box::new(10); // Box 智能指针
println!("x: {}", *x); // 解引用 Box,获取其值,输出: x: 10
}

二、& 借用引用

& 也是操作符

1. 作用

创建一个值的不可变引用,允许读而不获取所有权,该值在引用期间是只读的。

2. 用法

2.1. 不可变引用

fn main() {
let x = 10;
let y = &x; // y 是对 x 的不可变引用
println!("y: {}", y); // 输出: y: 10
}

2.2. 函数中的借用

fn print_value(x: &i32) {
println!("Value: {}", x);
} fn main() {
let a = 10;
print_value(&a); // 传递 a 的不可变引用
}

2.3. match 中使用

fn main() {
let reference = &4;
match reference {
&val => println!("Got a value via destructuring: {:?}", val),
}
}

2.4. 结构体中使用

struct Point<'a> {
x: &'a i32,
y: &'a i32,
}
fn main() {
let x = 10;
let y = 20;
let point = Point { x: &x, y: &y }; // 使用引用初始化结构体字段
println!("Point: ({}, {})", point.x, point.y); // 输出: Point: (10, 20)
}

2.5. 集合中使用

fn main() {
let vec = vec![1, 2, 3];
for val in &vec {
println!("Value: {}", val); // 输出: 1, 2, 3
}
}

2.6. 切片中使用

fn main() {
let s = String::from("hello");
let slice = &s[0..2]; // 创建字符串切片
println!("Slice: {}", slice); // 输出: Slice: he
}

三、mut 可变

mut 是一个关键字

1. 作用

声明一个变量或引用为可变的,可以修改其值。

2. 用法

2.1. 可变变量

fn main() {
let mut x = 5; // x 是可变的
x += 1;
println!("x: {}", x); // 输出: x: 6
}

2.2. 函数中可变参数

fn increment(mut num: i32) -> i32 {
num += 1;
num
}

2.3. 可变引用

fn main() {
let mut x = 5;
let y = &mut x;
*y += 1;
println!("{}", x); // 输出 6
}

2.4. 可变结构体

struct Point {
x: i32,
y: i32,
}
fn main() {
let mut p = Point { x: 0, y: 0 };
p.x = 5;
p.y = 10;
println!("Point: ({}, {})", p.x, p.y); // 输出 Point: (5, 10)
}

2.5. 可变元组

let mut tuple = (5, 10);
tuple.0 = 15;

2.6. match 中使用

match Some(10) {
Some(mut value) => {
value += 1;
println!("{}", value); // 输出 11
}
None => {},
}

2.7. 集合中使用

let mut vec = vec![1, 2, 3];
for num in &mut vec {
*num += 1;
}
println!("{:?}", vec);

四、&mut 可变借用引用

&mut 既不属于操作符也不属于关键字

1. 作用

创建一个值的可变引用,允许修改值而不获取所有权。

2. 用法

2.1. 可变引用

fn main() {
let mut x = 10;
{
let y = &mut x; // y 是对 x 的可变引用
*y += 5; // 修改 x 的值
} // y 的生命周期结束,此时 x 的可变借用结束
println!("x: {}", x); // 输出: x: 15
}

2.2. 函数中的可变引用

fn add_one(x: &mut i32) {
*x += 1;
} fn main() {
let mut a = 10;
add_one(&mut a); // 传递 a 的可变引用
println!("a: {}", a); // 输出: a: 11
}

2.3. 结构体中的可变引用

struct Point<'a> {
x: &'a mut i32,
y: &'a mut i32,
}
fn main() {
let mut x = 10;
let mut y = 20;
let point = Point { x: &mut x, y: &mut y }; // 使用可变引用初始化结构体字段
*point.x += 1;
*point.y += 1;
println!("Point: ({}, {})", point.x, point.y); // 输出: Point: (11, 21)
}

2.4. 集合中的可变引用

fn main() {
let mut vec = vec![1, 2, 3];
for val in &mut vec {
*val += 1; // 修改集合中的元素
}
println!("{:?}", vec); // 输出: [2, 3, 4]
}

2.5. match 中使用

fn main() {
let mut pair = (10, 20);
match pair {
(ref mut x, ref mut y) => {
*x += 1;
*y += 1;
println!("x: {}, y: {}", x, y); // 输出: x: 11, y: 21
},
}
}

2.6. 结构体中使用

struct Counter {
value: i32,
}
impl Counter {
fn increment(&mut self) {
self.value += 1;
}
}
fn main() {
let mut counter = Counter { value: 0 };
counter.increment(); // 使用可变引用调用方法
println!("Counter value: {}", counter.value); // 输出: Counter value: 1
}

五、ref 模式匹配中创建引用

ref 属于关键字

1. 作用

在模式匹配中借用值的不可变引用,而不是获取所有权。

2. 用法

2.1. 元组中使用

fn main() {
let tuple = (1, 2);
let (ref x, ref y) = tuple; // x 和 y 是对 tuple 中元素的不可变引用
println!("x: {}, y: {}", x, y); // 输出: x: 1, y: 2
}

2.2. match 中使用

fn main() {
let pair = (10, 20);
match pair {
(ref x, ref y) => {
println!("x: {}, y: {}", x, y); // x 和 y 是 pair 元素的不可变引用
}
}
}

2.3. if let / while let 中使用

// if let
fn main() {
let some_value = Some(42);
if let Some(ref x) = some_value {
println!("Found a value: {}", x); // x 是 some_value 的不可变引用
}
}
// while let
fn main() {
let mut stack = vec![1, 2, 3];
while let Some(ref x) = stack.pop() {
println!("Popped: {}", x); // x 是 stack 中最后一个元素的不可变引用
}
}

2.4. 函数中使用

fn print_ref((ref x, ref y): &(i32, i32)) {
println!("x: {}, y: {}", x, y); // x 和 y 是元组元素的不可变引用
}
fn main() {
let pair = (10, 20);
print_ref(&pair); // 传递 pair 的引用
}

2.5. for 循环中使用

fn main() {
let vec = vec![1, 2, 3];
for ref x in &vec {
println!("x: {}", x); // x 是 vec 中元素的不可变引用
}
}

六、ref mut 模式匹配中创建可变引用

ref mut 属于关键字

1. 作用

在模式匹配中借用值的可变引用,允许修改该值。

2. 用法

2.1. match 中使用

fn main() {
let mut pair = (10, 20);
match pair {
(ref mut x, ref mut y) => {
*x += 1;
*y += 1;
println!("x: {}, y: {}", x, y); // 输出: x: 11, y: 21
}
}
// pair 的值已经被修改
}

2.2. if let / while let 中使用

fn main() {
let mut some_value = Some(42);
if let Some(ref mut x) = some_value {
*x += 1;
println!("Found a value: {}", x); // 输出: Found a value: 43
}
}
fn main() {
let mut stack = vec![1, 2, 3];
while let Some(ref mut x) = stack.pop() {
*x += 1;
println!("Popped: {}", x); // 输出: Popped: 4, Popped: 3, Popped: 2
}
}

2.3. 函数中使用

fn increment_tuple((ref mut x, ref mut y): &mut (i32, i32)) {
*x += 1;
*y += 1;
} fn main() {
let mut pair = (10, 20);
increment_tuple(&mut pair); // 传递 pair 的可变引用
println!("pair: {:?}", pair); // 输出: pair: (11, 21)
}

2.4. 解构赋值

fn main() {
let mut pair = (10, 20);
let (ref mut x, ref mut y) = pair;
*x += 1;
*y += 1;
println!("x: {}, y: {}", x, y); // 输出: x: 11, y: 21
println!("{:?}", pair); // (11, 21)
}

七、总结

  • *:解引用操作符,用于访问指针或引用指向的值的类型。
  • &:借用操作符,用于创建不可变引用的类型,允许只读访问。
  • mut:关键字,用于声明可变变量或参数的类型,允许其值被修改。
  • &mut:借用操作符,用于创建可变引用的类型,允许读写访问。
  • ref:模式匹配中的关键字,用于创建不可变引用的类型,避免所有权转移。
  • ref mut:模式匹配中的关键字,用于创建可变引用的类型,允许修改引用的值。

Rust 中 *、&、mut、&mut、ref、ref mut 的用法和区别的更多相关文章

  1. ref和out的用法和区别。

    关于ref和out的用法和区别在网上已经有很多的解释,这里只不过是写下对于我而说比较容易理解的解释. ref和out都可以用来在函数中返回数据,类似于c++中指针. 参数 Ref Out 是否一定需要 ...

  2. ref 和 out 的用法和区别以及params用法

    方法参数可以划分为一下四种类型1 值参数:声明时不含任何修饰符2 引用参数:以ref修饰符声明3 输出参数:以out修饰符声明4 参数数组:以params修饰符声明 引用参数和输出参数不创建新的存储位 ...

  3. [置顶] perl脚本中defined,exists和delete关键字的用法和区别

    刚学习perl脚本的时候,喜欢频繁使用defined关键字判断一个hash中某个key是否存在,后来程序出了问题才去perl官方文档查看关于defined关键字的准确使用方法.因此,这里我把perl中 ...

  4. [置顶] mysql中的set和enum类型的用法和区别

    mysql中的enum和set其实都是string类型的而且只能在指定的集合里取值,  不同的是set可以取多个值,enum只能取一个值.   CREATE TABLE `20121101_t` ( ...

  5. PHP中MySQL、MySQLi和PDO的用法和区别

    PHP的MySQL扩展(优缺点) 设计开发允许PHP应用与MySQL数据库交互的早期扩展.mysql扩展提供了一个面向过程 的接口: 并且是针对MySQL4.1.3或更早版本设计的.因此,这个扩展虽然 ...

  6. PHP中MySQL、MySQLi和PDO的用法和区别【原创】

    对于一个初学PHP的自己,对数据库的连接有着很大的疑惑,从Java转到PHP.数据库连接变了,以前只知道JDBC连接数据库,或者直接用框架调用,对于的PHP的数据库连接方式,及其应用.不是很了解,于是 ...

  7. JavaScript ES6中export、export default、import用法和区别

    相信熟悉JS ES6的同学都知道export.export default是导出,import是导入的意思. 那么问题就来了, 1.import 导入要怎么用? 2.export.export def ...

  8. c#中关键词out和ref的区别

    c#中关键词out和ref用来表明以传引用的方式传递参数. 区别如下: 如果方法的参数用out标记,表示方法被调用前不需初始化参数,方法内不能读取此参数的值,在方法返回前必须向此参数写入值: 如果方法 ...

  9. Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别

    Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...

  10. (转)Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别

    Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...

随机推荐

  1. Vue cli之路由router

    一.安装路由 Vue-router用于提供给vue项目在开发中用于绑定url和组件页面的关系的核心插件. 默认情况下,vue没有提供路由的功能,所以我们使用vue-router,并需要在项目根目录. ...

  2. HTML——input之单行文本框

    在 HTML 中,把 <input> 标签的 type 属性设置为 text 可以表示单行文本框,又叫做常规文本框.具体语法格式如下: <input type="text& ...

  3. WPF在ListView中绑定Command命令的写法

    假定:ViewModel中有一个数据源叫Persons,有一个命令叫DoCommand,通过System.Windows.Interactivity触发器绑定鼠标MouseUp事件,当UI端绑定了Da ...

  4. 用Yacht管理docker容器

    今天是六一儿童节,祝大小朋友们节日快乐! 从今天开始起,防范区的上海市民可以自由出入小区了.始于愚人节,终于儿童节,整整两个月时间,终于迎来了期盼已久的自由和正常. 周一上午的的核酸可能是我们最后一次 ...

  5. 拼多多面试:Netty如何解决粘包问题?

    粘包和拆包问题也叫做粘包和半包问题,它是指在数据传输时,接收方未能正常读取到一条完整数据的情况(只读取了部分数据,或多读取到了另一条数据的情况)就叫做粘包或拆包问题. 从严格意义上来说,粘包问题和拆包 ...

  6. Linux驱动--IOCTL实现

    参考:[Linux]实现设备驱动的ioctl函数_哔哩哔哩_bilibili.<Linux设备驱动程序(中文第三版).pdf> 1 用户空间ioctl 用户空间的ioctl函数原型,参数是 ...

  7. numpy基础--线性代数

    以下代码的前提:import numpy as np 线性代数(如矩阵乘法.矩阵分解.行列式以及其他方阵数学等)是任何数组库的重要组成部分.numpy提供了一个用于矩阵乘法的dot函数(既是一个数组方 ...

  8. 通过USB口扩展wan口上网(4G上网卡)

    通过USB口扩展wan口上网(4G上网卡) 一.前言 现爱快可支持通过USB口扩展wan口上网,不再居于地点的限制,随时随地流畅上网. 二.具体配置 现在有两种设备可以实现通过USB口转化为wan口上 ...

  9. TypeScript keyof

    keyof 是 TypeScript 中的一个关键字,用于获取一个类型的所有键(属性名)构成的联合类型.它主要用于在类型系统中引用对象类型的键. 以下是一些 keyof 的用法和示例: 1. 获取对象 ...

  10. THUWC 2024 游记

    其实这个游记也没啥好写的-- day 0 上午做动车两个小时到重庆,路上玩了 1.5h 的星露谷. 下午去巴蜀中学报道试机,系统是 Ubuntu Jammy,大大的好评,只是桌面是 Xubuntu/X ...