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}
}
相关文章:
Rust踩雷笔记(7)——两个链表题例子初识裸指针
目录 leetcode 234leetcode 19 leetcode 234 题目在这https://leetcode.cn/problems/palindrome-linked-list/,leetcode 234的回文链表,思路很简单,就是fast和slow两个指针,fast一次移动两个、slow一次一个,最后slow指…...
用什么命令看Linux系统的体系架构
要查看Linux系统的体系架构,可以使用uname命令。在终端中运行以下命令: uname -m该命令将返回系统的体系架构,例如x86_64表示64位系统,i686表示32位系统。 uname 使用方法 uname命令用于获取操作系统的相关信息。它可以用于显示…...
消息中间件大揭秘:选择之前你必须知道的关键信息
Hello大家好!我是小米,很高兴再次和大家见面!今天的话题非常精彩,我们将深入探讨消息中间件,并了解一些常见的消息队列:RabbitMQ、RocketMQ、Kafka以及Redis。如果你正在准备面试,或者只是对这些…...
【Unity基础】4.动画Animation
【Unity基础】4.动画Animation 大家好,我是Lampard~~ 欢迎来到Unity基础系列博客,所学知识来自B站阿发老师~感谢 (一)Unity动画编辑器 (1)Animation组件 这一张我们要学习如何在unity编辑器中&…...
FreeRTOS移植以及核心功能
文章目录 freertos和ucos区别,优缺点比较移植步骤核心功能内存管理(5种内存管理策略)FreeRTOS任务调度算法有三种时间管理通信管理 栈管理 freertos和ucos区别,优缺点比较 FreeRTOS(Free Real-Time Operating System&…...
重装系统(配置环境)
这里写目录标题 0.重装系统1.python1.1 anaconda1.2 pycharm1.3 深度学习环境配置 2.java2.1.安装JDK2.2.配置JDK环境变量2.3IDEA2.4 Maven 3.大数据3.1 虚拟机3.2 Hadoop平台3.3 存储3.4 采集3.5 计算3.6 查询3.7 可视化 0.重装系统 // An highlighted block var foo bar;1.…...
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…...
Vue3快速上手
1.Vue3简介 2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址:Release v3.0.0 One Piece vuejs/core GitHub 2.Vue3带…...
二叉搜索树(BST,Binary Search Tree)
文章目录 1. 二叉搜索树1.1 二叉搜索树概念1.2 二叉搜索树的查找1.3 二叉搜索树的插入1.4 二叉搜索树的删除 2 二叉搜索树的实现3 二叉搜索树的应用3.1二叉搜索树的性能分析 1. 二叉搜索树 1.1 二叉搜索树概念 二叉搜索树又称二叉排序树,它或者是一棵空树…...
分析key原理
总结: key是虚拟dom对象的标识,当数据发生变化时,vue会根据新数据生成新的虚拟dom,随后vue进行新虚拟dom与旧虚拟dom的差异比较 比较规则: ①旧虚拟dom中找到了与新虚拟dom相同的key 若虚拟dom中的内容没变,…...
[CISCN2019 华东南赛区]Web11 SSTI
这道SSTI 差点给我渗透的感觉了 全是API 我还想去访问API看看 发现这里读取了我们的ip 我们抓包看看是如何做到的 没有东西 我们看看还有什么提示 欸 那我们可不可以直接修改参数呢 我们传递看看 发现成功了 是受控的 这里我就开始没有思路了 于是看了wp 说是ssti 那我们看…...
百度春招C++后端面经总结
这次的面经,主要都是问操作系统、网络编程、C++ 这三大方向。 能明显感觉到,C++面试和Java或者Go面试重点,Java/Go主要是问MySQL、Redis。 一、介绍一下webserver项目 服务器开始运行,创建(初始化)线程池(IO密集型,线程数n+1); 创建 epoll 对连接进行监听 监听到连…...
小程序开发一个多少钱啊
在今天的数字化时代,小程序已经成为一种非常流行的应用程序形式。由于它们的便捷性、易用性和多功能性,小程序吸引了越来越多的用户和企业。但是,很多人在考虑开发一个小程序时,都会遇到同一个问题:开发一个小程序需要…...
C# 随机数生成 Mersenne Twister 马特赛特旋转演算法 梅森旋转算法
NuGet安装MathNet.Numerics 引用: using MathNet.Numerics.Random; /// <summary>/// 包括lower,不包括upper/// </summary>/// <param name"lower"></param>/// <param name"upper"></param>/// <para…...
C++进阶(二)
目录 1、Vector2D 默认构造、重载 2、char 深度理解 3、深度理解简单的类操作 1、Vector2D 默认构造、重载 #include <iostream> #include <cmath>class Vector2D { private:double x; // X坐标double y; // Y坐标public:// 默认构造函数,将向量初…...
zoneinfo
在Linux系统中,zoneinfo是一个包含了世界各地时区信息的目录,通常位于/usr/share/zoneinfo。这个目录下的子目录和文件名对应了各个时区的名称。例如,/usr/share/zoneinfo/America/Los_Angeles文件就包含了美国洛杉矶的时区信息。 你可以通过…...
基于微信小程序的实验室预约管理系统设计与实现
前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 👇🏻…...
腾讯mini项目-【指标监控服务重构】2023-08-17
今日已办 定位昨日发现的问题 来回测试发现依然出现该问题 将 pub/sub 的库替换为原来官方基于 sarama 的实现,发现问题解决了,所以问题的根本是 kafkago 这个库本身存在问题 依据官方的实现,尝试自定义实现 pub/sub sarama 与 kafka-go …...
前端需要知道的计算机网络知识----网络安全,自学网络安全,学习路线图必不可少,【282G】初级网络安全学习资源分享!
网络安全(英语:network security)包含网络设备安全、网络信息安全、网络软件安全。 黑客通过基于网络的入侵来达到窃取敏感信息的目的,也有人以基于网络的攻击见长,被人收买通过网络来攻击商业竞争对手企业࿰…...
#循循渐进学51单片机#定时器与数码管#not.4
1、熟练掌握单片机定时器的原理和应用方法。 1)时钟周期:单片机时序中的最小单位,具体计算的方法就是时钟源分之一。 2)机器周期:我们的单片机完成一个操作的最短时间。 3)定时器:打开定时器“储存寄存器…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
