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 中使用 Axios

    安装 axios: 1 npm install axios --save-dev 接着在src目录下创建一个http.js脚本中,导入axios并通过create方法实例化一个http请求对象,这样我 ...

  2. golang sync.once done 热路径

    sync.once 为什么会将done放在结构体第一个字段,就能够提升性能了? 我们先来看看sync.once的结构体: // Once is an object that will perform ...

  3. Json.NET Converting between JSON and XML

    Json.NET supports converting JSON to XML and vice versa using the XmlNodeConverter. Elements, attrib ...

  4. weinre  远程实时调试手机上的Web页面 JAVASCRIPT远程调试

    版权归作者所有,任何形式转载请联系作者.作者:U_U(来自豆瓣)来源:https://www.douban.com/note/289846168/ 调试前端页面我一直使用着神器Chrome开发人员工具 ...

  5. docker构建镜像——Dockerfile

    from RUN CMD EXPOSE LABEL ENV COPY 格式 COPY [--chown=<用户>:<组>]<源>...<目的> COPY ...

  6. linux系统,kafka常用命令

    kafka版本过高所致,2.2+=的版本,已经不需要依赖zookeeper来查看/创建topic,新版本使用 --bootstrap-server替换老版本的 --zookeeper-server. ...

  7. 使用 JMX-Exporter 监控 Kafka 和 Zookeeper

    JVM 默认会通过 JMX 的方式暴露基础指标,很多中间件也会通过 JMX 的方式暴露业务指标,比如 Kafka.Zookeeper.ActiveMQ.Cassandra.Spark.Tomcat.F ...

  8. n. Elasticsearch JAVA API操作

    引言 Elasticsearch所支持的客户端连接方式有两种 Transport 连接 底层使用socket连接,用官方提供的TransPort客户端,网络IO框架使用的是netty Http连接(R ...

  9. 如何判断APP页面是原生还是H5

    如何判断APP页面是原生还是H5 1.打开设置,搜索"开发者选项",点击"开发者选项" 华为手机进入开发者模式方法 1.打开华为手机的[设置],找到并点击进入[ ...

  10. JavaScript:Function:函数(方法)对象

    <!DOCTYPE html><html>    <head>        <meta charset="utf-8">      ...