Rust踩雷笔记(7)——两个链表题例子初识裸指针

目录

      • leetcode 234
      • leetcode 19

leetcode 234

题目在这https://leetcode.cn/problems/palindrome-linked-list/,leetcode 234的回文链表,思路很简单,就是fast和slow两个指针,fast一次移动两个、slow一次一个,最后slow指向的链表反转后和head比较就行了。

很简单一题,但考虑一个问题:slow和fast是什么形式?由于rust有所有权机制,所以slow和fast只能是借用,并且还不能是可变借用(可变借用只能有一个、可变借用和不可变借用不能同时存在)。

所以slow和fast只能是两个不可变借用,直接放上代码:

// Definition for singly-linked list.
// #[derive(PartialEq, Eq, Clone, Debug)]
// pub struct ListNode {
//   pub val: i32,
//   pub next: Option<Box<ListNode>>
// }
//
// impl ListNode {
//   #[inline]
//   fn new(val: i32) -> Self {
//     ListNode {
//       next: None,
//       val
//     }
//   }
// }
impl Solution {pub fn reverse(mut head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {let mut prev = None;while let Some(mut node) = head {head = node.next;node.next = prev;prev = Some(node);}prev}pub fn is_palindrome(head: Option<Box<ListNode>>) -> bool {// 快慢指针,fast一次移动2个,slow一次移动1个,slow会停留在中间偏后的位置// 反转slow为头结点的链表// 比较head和slow两个链表,直到head的长度达到即停止let p = head.as_ref().unwrap();if p.next.is_none() {return true;}let mut head = head;let mut slow = &head;let mut fast = &head;while slow.is_some() && fast.is_some() {slow = &(slow.as_ref().unwrap().next);fast = &(fast.as_ref().unwrap().next);if fast.is_none() {break;}fast = &(fast.as_ref().unwrap().next);}// let s =  slow  as *const Option<Box<ListNode>> as * mut  Option<Box<ListNode>>;let s = slow as *const Option<Box<ListNode>> as *mut Option<Box<ListNode>>;let mut head2 = unsafe {(*s).take()};head2 = Solution::reverse(head2);let mut flag = true;while let (Some(node1), Some(node2)) = (head.as_ref(), head2.as_ref()) {if node1.val != node2.val {flag = false;break;}head = head.unwrap().next;head2 = head2.unwrap().next;}flag}
}

主要注意代码中的

let s = slow as *const Option<Box<ListNode>> as *mut Option<Box<ListNode>>;
let mut head2 = unsafe {(*s).take()
};

这里我的本意是写成这样:

let mut head2 = slow.take();

但是slow是不可变借用,这里就会报错:

cannot borrow `*slow` as mutable, as it is behind a `&` reference
`slow` is a `&` reference, so the data it refers to cannot be borrowed as mutable

大意就是slow不是可变借用,take()的作用是拿走物主对某个东西的所有权,然后将所有权交给另一个人。你借一个人的东西,并且不被允许改变这个东西,那么你肯定不能把这个东西的所有权扔给别人对吧。

这个时候就需要裸指针的概念了,如果不会请移步:
https://kaisery.github.io/trpl-zh-cn/ch19-01-unsafe-rust.html
链接中截图关键内容:
在这里插入图片描述
注意*const*mut是不可变、可变两种裸指针,星号不是解引用,而是类型的一部分。⚠️注意是将不可变引用变成*const类型的裸指针,可变引用变成*mut类型的裸指针,所以前面的代码里写的是:

let s = slow as *const Option<Box<ListNode>> as *mut Option<Box<ListNode>>;

slow是不可变引用&Option<Box<ListNode>>,所以先转换为*const Option<Box<ListNode>>,再转换为*mut Option<Box<ListNode>>类型。

然后要在unsafe代码块中使用它,记得写法是(*s).take()拿到所有权赋给head2

let mut head2 = unsafe {(*s).take()
};

至此head2就是slow引用的那个节点了。

leetcode 19

题目是删除链表中倒数第n个节点,要求一趟遍历。

这里也可以使用裸指针,只要是如下场景都可以考虑裸指针:
(1)&和&mut同时出现,又不可避免。那么如果已经有了&,还需要一个&mut的话,可以创建裸指针mut;
(2)需要通过&不可变引用进行改变,那么可以将&转换为
const,再转换为*mut,此时就和&mut作用一致了。

// Definition for singly-linked list.
// #[derive(PartialEq, Eq, Clone, Debug)]
// pub struct ListNode {
//   pub val: i32,
//   pub next: Option<Box<ListNode>>
// }
//
// impl ListNode {
//   #[inline]
//   fn new(val: i32) -> Self {
//     ListNode {
//       next: None,
//       val
//     }
//   }
// }
impl Solution {pub fn remove_nth_from_end(head: Option<Box<ListNode>>, n: i32) -> Option<Box<ListNode>> {// 从头结点开始向后走n - 1步let mut dummy = Some(Box::new(ListNode::new(0)));dummy.as_mut().unwrap().next = head;let mut p_tail = &(dummy.as_ref().unwrap().next);let mut cnt = 0;    // 向后走了几步while cnt < n - 1 {cnt += 1;p_tail = &(p_tail.as_ref().unwrap().next);}let mut delete_next = &dummy;while p_tail.as_ref().unwrap().next.is_some() {p_tail = &(p_tail.as_ref().unwrap().next);delete_next = &(delete_next.as_ref().unwrap().next);}// 至此,我们只需要删除delete_next节点的下一个节点// 然后返回dummy的下一个节点即可// 通过裸指针拿到delete_next节点的下一个的下一个节点的所有权let mut need_take = &(delete_next.as_ref().unwrap().next);need_take = &(need_take.as_ref().unwrap().next);// need_take是不可变引用,先拿到*mut类型的裸指针,便可拿到need_take引用的节点所有权let mut temp1  = need_take as *const Option<Box<ListNode>> as *mut Option<Box<ListNode>>;let mut temp = unsafe {(*temp1).take()};// 我们需要将need_take的所有权赋给delete_next节点的next,所有权现在给了temp// delete_next是不可变引用,我们要修改它引用的节点的next,就可以通过可变裸指针// 不可变引用需要先转换为*const再转换为*mutlet mut delete_next_temp = delete_next as *const Option<Box<ListNode>> as *mut Option<Box<ListNode>>;unsafe {(*delete_next_temp).as_mut().unwrap().next = temp;}dummy.unwrap().next}
}

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

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

相关文章

docker系列-报错以及解决指南

1. windows运行docker报错Windows Hypervisor is not presentDocker Desktop is unable to detect a Hypervisor.Hardware assisted virtualization and data execution protection must be enabled in the BIOS. Docker Desktop - Windows Hypervisor is not presentDocker D…

java集合之迭代器遍历元素

集合遍历 遍历、迭代、逐个获取容器中的元素 Iterable接口 实现了Iterable接口的类是可以遍历的&#xff0c;因为Iterable接口是Collection接口的父接口&#xff0c;而所有单列集合类都实现了Collection接口&#xff0c;从而也都实现了Iterable接口&#xff0c;所以所有单列集…

解决Springboot使用Junit测试时对数据库的修改无效

现象 在使用Junit做单元测试的过程中&#xff0c;比如对mybatis的dao进行单元测试&#xff0c;发现对数据库的select操作正常&#xff0c;可以获取数据&#xff0c;但insert、update、delete操作即使运行不报错&#xff0c;仍然不能不能对数据产生修改和插入。 原因和解决 原…

StarRocks 社区:从初生到两周年的进化之路

2021 年 9 月 8 日&#xff0c;StarRocks 开源社区诞生。从第一天开始&#xff0c;我们怀揣着“打造世界一流的数据分析产品”的梦想&#xff0c;踏上了星辰大海的征途。 两年间&#xff0c;StarRocks 在 GitHub 上收获了 5.4K Stars&#xff0c;产品共迭代发布了 90 余个版本&…

go语言 反向代理

实现简单的http反向代理 还没有加入负载均衡 新手推荐 下游服务器代码 package mainimport ("fmt""io""log""net/http""os""os/signal""syscall""time" )type RealServer struct {Addr str…

嵌入式:驱动开发 Day9

作业&#xff1a;通过platform总线驱动实现 a.应用程序通过阻塞的io模型来读取number变量的值 b.number是内核驱动中的一个变量 c.number的值随着按键按下而改变&#xff08;按键中断&#xff09; 例如number0 按下按键number1 ,再次按下按键number0 d.在按下按键的时候需要同时…

Python 公里与海里换算

""" 公里与海里换算知识点&#xff1a;1、换算公式&#xff1a;海里 公里 / 1.8522、input()、print()函数3、变量类型转换&#xff0c;整形int与字符串str转换&#xff0c;可以用type()函数验证4、字符串拼接&#xff0c;例如&#xff1a;123 456 1234565、…

Vue3快速上手

1.Vue3简介 2020年9月18日&#xff0c;Vue.js发布3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;海贼王&#xff09;耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址&#xff1a;Release v3.0.0 One Piece vuejs/core GitHub 2.Vue3带…

搜款网VVIC根据ID取商品详情 API 关键词搜索商品列表

搜款网是一家服装批发平台&#xff0c;提供多个品牌和供应商的服装、鞋子、箱包等商品供采购者选择&#xff0c;为了获取商品详情&#xff0c;您需要使用搜款网的API接口。 建议您联系搜款网的客服或开发者&#xff0c;以获取更多关于API接口的信息&#xff0c;包括使用方法、…

数据标准化

1、均值方差标准化(Z-Score标准化) 计算过程&#xff1a; 对每个属性/每列分别进行一下操作&#xff0c;将数据按属性/按列减去其均值&#xff0c;并除以其方差&#xff0c;最终使每个属性/每列的所有数据都聚集在均值为0&#xff0c;方差为1附近。 公式&#xff1a;(x-mean(x…

M-LAG简介

定义 M-LAG&#xff08;Multichassis Link Aggregation Group&#xff09;即跨设备链路聚合组&#xff0c;是一种实现跨设备链路聚合的机制&#xff0c;将一台设备与另外两台设备进行跨设备链路聚合&#xff0c;从而把链路可靠性从单板级提高到了设备级&#xff0c;组成双活系…

Linux CentOS7 wc命令

wc命令的功能为统计指定文件中的字节数、字数、行数, 并将统计结果显示输出。 录入 man wc 可以查看相关信息 基本语法&#xff1a; wc [选项] 文件… 说明&#xff1a;该命令统计给定文件中的字节数、字数、行数。如果没有给出文件名&#xff0c;则从标准输入读取。wc同时也…

C语言进阶第三课-----------指针的进阶----------后续版

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

docker总结

Docker实用篇 0.学习目标 1.初识Docker 1.1.什么是Docker 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&#xff0c;依赖的组件非常多&#xff0c;不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署…

ddtrace 系列篇之 dd-trace-java 项目编译

dd-trace-java 是 Datadog 开源的 java APM 框架&#xff0c;本文主要讲解如何编译 dd-trace-java 项目。 环境准备 JDK 编译环境(三个都要&#xff1a;jdk8\jdk11\jdk17) Gradle 8 Maven 3.9 (需要 15G 以上的存储空间存放依赖) Git >2 (低于会出现一想不到的异常&#xf…

大语言模型之十-Byte Pair Encoding

Tokenizer 诸如GPT-3/4以及LlaMA/LlaMA2大语言模型都采用了token的作为模型的输入输出&#xff0c;其输入是文本&#xff0c;然后将文本转为token&#xff08;正整数&#xff09;&#xff0c;然后从一串token&#xff08;对应于文本&#xff09;预测下一个token。 进入OpenAI官…

Learn Prompt-Prompt 高级技巧:MetaGPT

MetaGPT是一项引起广泛关注的研究成果&#xff0c;它引入了一个将人工工作流程与多智能体协作无缝集成的框架。通过将标准化操作&#xff08;SOP&#xff09; 程序编码为提示&#xff0c;MetaGPT确保解决问题时采用结构化方法&#xff0c;从而减少出错的可能性。 &#x1f389…

【深度学习】ONNX模型快速部署【入门】

【深度学习】ONNX模型快速部署【入门】 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】ONNX模型快速部署【入门】前言搭建打包环境打包可执行文件总结 前言 之前的内容已经尽可能简单、详细的介绍CPU【Pytorch2ONNX】和GPU【Pyto…

蓝桥杯打卡Day12

文章目录 接龙数列冶炼金属 一、接龙数列OJ链接 本题思路:本题是一道经典的dp问题&#xff0c;设第i个数的首位数字是first&#xff0c; 末位数字是last。因为第i个数只可能加到一个以first结尾的接龙数列中使得这个接龙数列长度加1并且结尾数字变成last.所以状态转移方程为d…

设计模式_解释器模式

解释器模式 案例 角色 1 解释器基类 &#xff08;BaseInterpreter&#xff09; 2 具体解释器1 2 3... (Interperter 1 2 3 ) 3 内容 (Context) 4 用户 (user) 流程 (上下文) ---- 传…