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)定时器:打开定时器“储存寄存器…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...