C++:迭代器的封装思想
C++:迭代器的封装思想
- list迭代器实现
- 反向迭代器实现
本博客将通过实现list的迭代器,以及它的反向迭代器,来帮助大家理解迭代器的底层逻辑,以及封装思想。
list迭代器实现
迭代器是一个遍历容器的工具,其可以通过自增自减来改变位置,通过解引用来访问节点,也就是模仿指针的行为。这为算法库提供了统一的方式来访问容器,也降低了用户的学习成本,可以用相同的方式来访问不同的容器。
那么迭代器是如何做到模仿指针行为的?
这还要归功于运算符重载这一设计,在类中,我们可以通过运算符重载来决定一个类在面对不同运算符时的行为,那么我们是否可以将迭代器封装为一个类,然后利用运算符重载,使得迭代器可以使用++,–,*这样的操作符,从而模仿指针的行为呢?
STL的底层迭代器就是利用这样的方式实现的。
我们先来看到list
的基本结构:
list
节点:
template <class T>
struct list_node
{list_node<T>* _next;list_node<T>* _prev;T _data;
};
这是一个list
的节点list_node
,其有三个成员:_prev
指向上一个节点,_next
指向下一个节点,_data
存储当前节点的数据。
template <class T>class list{typedef list_node<T> node;private:node* _head;};
这是一个list
类,其将节点list_node<T>
重命名为了node
,方便后续使用。
唯一一个成员变量是哨兵位头节点指针_head
。
接下来我们就讨论要如何设计这个list
的迭代器:
毫无疑问,我们需要把这个迭代器封装为一个类,而这个类的内部我们需要什么,才能让迭代器访问不同的节点呢?
想要访问不同的节点,毫无疑问就需要不同节点的指针,所以我们的迭代器需要把一个指向节点的指针给封装起来,然后利用运算符重载,改变这个指针的行为,从而实现迭代器。
现在我们将这个迭代器命名为__list_iterator
,先看看基础结构:
template <class T>
struct __list_iterator
{typedef list_node<T> node;node* _node;
};
为了方便我们使用节点的指针,我们重命名list_node<T>
为node
,而迭代器内部指向节点的指针名为_node
。
构造函数:
代码如下:
__list_iterator(node* n): _node(n)
{}
这就是一个很简单的初始化过程,这里不过多赘述了,那么我们要如何使用这个迭代器呢?
看看list
类中获取迭代器的函数:
typedef __list_iterator<T> iterator;iterator begin()
{return iterator(_head->_next);
}iterator end()
{return iterator(_head);
}
先将我们的迭代器重命名为iterator
,方便后续使用。
可以看到,我们的begin()
函数就是返回了哨兵位节点的后一个节点,也就是第一个节点的指针,但是普通的指针的++,–操作不符合我们的要求,于是我们利用iterator(_head->_next)
这个方式,利用这个指针来构造一个匿名对象,也就是迭代器的匿名对象,此时我们就完成了指针的封装,得到的指针就是被我们修改了行为后的迭代器了。
end()
函数同理,iterator(_head)
构造一个迭代器,将指针进行封装,修改其行为。
接下来我们回到迭代器的实现:
operator++:
我们希望我们的迭代器可以在++的时候到达下一个节点的位置,也就是_node = _node->_next
这样的行为。
所以我们的需求就明确了,当迭代器++的时候,实际发生的是_node = _node->_next
而不是简单的指针偏移。
先看到我们的实现:
__list_iterator<T> & operator++()
{_node = _node->_next;return *this;
}
++是要进行返回的,将自增后的节点作为返回值,所以最后我们还要return *this;
,将修改后的节点作为返回值。
后置++同理:
__list_iterator<T>& operator++(int)
{__list_iterator<T> tmp(*this);_node = _node->_next;return tmp;
}
由于后置++需要将自增前的值作为返回值,所以我们要先拷贝一份原先的值tmp
,自增完成后,将原先的值tmp
返回。
为了简化代码,我们可以将__list_iterator<T>
重命名为self
代表迭代器自己的类型。
最后代码如下:
typedef __list_iterator<T> self;self& operator++()
{_node = _node->_next;return *this;
}self& operator++(int)
{self tmp(*this);_node = _node->_next;return tmp;
}
这样一来,我们的迭代器++,表面上和指针自增一样,但是底层却是_node = _node->_next
到达下一个节点的位置了。
operator–:
迭代器–同理,我们需要实现迭代器到达上一个节点,其实就是_node = _node->_prev
。
实现如下:
self& operator--()
{_node = _node->_prev;return *this;
}self& operator--(int)
{self tmp(*this);_node = _node->_prev;return tmp;
}
迭代器判断相等:
想要判断两个迭代器是否相等,其实就是判断其内部封装的指针_node
是否相等。
代码如下:
bool operator!=(const self& s)
{return _node != s._node;
}bool operator==(const self& s)
{return _node == s._node;
}
这个比较简单,不做赘述了。
operator*:
*是迭代器中十分重要的操作符,指针就是利用解引用来访问指向内容的,迭代器就模仿指针,也通过解引用来访问节点值。
迭代器内部的成员_node是指向节点的指针,那么访问这个节点的值就是:_node->_data
了。
所以解引用代码如下:
T& operator*()
{return _node->_data;
}
但是这个代码有一个问题,那就是:如果我们的list
被const
修饰了怎么办?
这样的话,由于我们返回的是T&
,而这个_data就有可能会被修改,这就不符合const的行为了。
是否我们要写一个重载,比如这样:
T& operator*()
{return _node->_data;
}const T& operator*()
{return _node->_data;
}
这是不行的,因为两个函数只有返回值不同,并不构成重载。
我们只希望返回值的类型不同,这要怎么办?
注意:我们的迭代器是利用模板生成的,而模板最大的用处就是泛型编程,可以无视类型的限制,我们完全可以给模板多传一个参数,让第二个参数作为operator*
的返回值。
//-----迭代器-----
template <class T, class Ref>
struct __list_iterator
{typedef __list_iterator<T, Ref> self;Ref operator*(){return _node->_data;}
};
这样,当我们需要普通迭代器,第二个参数Ref
就传入T&
,如果需要const
迭代器,那么第二个参数就传入const T&
。
不过要注意的是,刚刚我们重命名了一个self
, 即typedef __list_iterator<T> self
,此时由于模板参数改变,这个重命名也要一起改变:typedef __list_iterator<T, Ref> self
。
现在我们就可以在list
中加入const
迭代器了,接下来让类中定义的迭代器一起改变:
template <class T>
class list
{typedef __list_iterator<T, T&> iterator;typedef __list_iterator<T, const T&> const_iterator;//普通迭代器iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}//const迭代器const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}
};
看到两行typedef
:
typedef __list_iterator<T, T&> iterator;
typedef __list_iterator<T, const T&> const_iterator;
当我们传入的第二个模板参数为T&
,那么解引用的返回值就是可以修改的,此时就是一般的迭代器iterator
。
当我们传入的第二个模板参数为const T&
,那么解引用的返回值就是不可以修改的,此时就是const
迭代器const_iterator
。
相比于开始,我们现在多了一个迭代器const_iterator;
,我们的this
指针被const
修饰时,说明此时需要调用const
迭代器,那么我们就返回const_iterator
类型的迭代器。
const_iterator begin() const
{return const_iterator(_head->_next);
}const_iterator end() const
{return const_iterator(_head);
}
operator->:
接下面我们看到最后一个问题,那就是类的嵌套问题,假设我们的list内部是一个A类:
class A
{
public:int num;
};
那么如果我们想要通过迭代器访问A类的num成员,要怎么做?
假设我们有一个list
的迭代器it
,接下来我用it
尝试访问这个A的成员num
。
(*it).num
先解引用迭代器(*it)
,此时就得到了list
内部的A类,然后再利用.
来访问内部的num
成员。
这样访问是没有问题的,但是我们的迭代器是模仿指针的行为,我们会对一个指针先解引用,再用点操作符访问成员吗?
我们完全可以指针 -> 成员
这样访问。
也就是说,我们还要对迭代器重载一个->
操作符,实现这种直接访问的方式
代码:
T* operator->()
{return &_node->_data;
}
我们的返回值是_data
的地址,而_data
就是A类,所以我们可以就得到了一个A类的指针,此时T*
就是其实就是A*
。
那么我们看看现在要如何访问:
list.operator->()->num
你也许不是很能理解以上代码,我们拆解一下:
list.operator->()
返回了一个A*
类型的指针,而A*
类型的指针可以直接访问num
:
A* ptr;
ptr->num
所以以上代码list.operator->()->num
就可以访问到num
这个成员了。
而.operator->()
其实就是->
操作符,所以可以变形为以下代码:
list->->num
连用->->
不太美观,也容易让人费解,但是编译器会将两个->
优化为一个->
,所以此时我们已经可以直接像指针一样访问成员了:
list->num
我们再回顾一遍推导过程:
list.operator->()->num
==list->->num
==list->num
这个访问和刚刚的operator*
会遇到同样的问题,那就是const问题,所以我们要传入第三个模板参数Ptr
,来控制operator->
的返回值:
template <class T, class Ref, class Ptr>
struct __list_iterator
{Ptr operator->(){return &_node->_data;}
};
在list
中:
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
至此,我们就实现了一个list
的迭代器了。
代码展示:
template <class T, class Ref, class Ptr>
struct __list_iterator
{typedef list_node<T> node;typedef __list_iterator<T, Ref, Ptr> self;node* _node;__list_iterator(node* n): _node(n){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}self& operator++(){_node = _node->_next;return *this;}self& operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self& operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const self& s){return _node != s._node;}bool operator==(const self& s){return _node == s._node;}
};
反向迭代器实现
那么我们要如何实现反向迭代器呢?
一开始我们实现正向迭代器的时候,遇到的问题就是:原生指针的行为不符合我们的要求,于是我们将原生指针进行了封装,利用运算符重载来修改其行为。
那么我们的反向迭代器还需要封装一个原生指针吗?
其实我们可以换一个思路:现在我们有正向迭代器,而正向迭代器并不符合反向迭代器的预期行为,我们不妨对正向迭代器进行一次封装,让其++变成–,–变成++,这不就是一个反向迭代器了吗?
结构如下:
template <class Iterator, class Ref, class Ptr>
struct ReverseIterator
{Iterator _cur;
};
我们定义了一个反向迭代器的类ReverseIterator
,在内部封装了一个迭代器Iterator _cur
,接下来我们就重载这个反向迭代器,让其行为符合预期:
先看看我们在list中是如何定义反向迭代器的:
template <class T>class list{typedef ReverseIterator<iterator, T&, T*> reverse_iterator;//反向迭代器reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}};
首先我们重命名了反向迭代器typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
,其第一个模板参数为iterator
,也就是我们封装的正向迭代器。
随后在rbegin()
中,我们直接将end()
返回的末尾迭代器,作为我们反向迭代器的起始迭代器rbegin()
;
将begin()
返回的正向迭代器的起始迭代器,作为我们反向迭代器的末尾迭代器。
注意,end()返回的是最后一个元素的后面一个位置,所以我们在后续++,–操作时,要进行其他的操作,来矫正这个位置的偏差。
operator++:
现在由于我们是反向迭代器,我们的反向迭代器++,其实就是正向迭代器的–。
代码如下:
self& operator++()
{--_cur;return *this;
}
operator*
由于我们的迭代器位置是往后偏一位的,所以我们要返回前一个位置的迭代器而不是当前位置的迭代器:
Ref operator*()
{Iterator tmp = _cur;--tmp;return *tmp;
}
我们用tmp
拷贝了一份当前的迭代器,随后--tmp
,将其往前走一个位置,再返回tmp
位置的迭代器,这样就可以矫正我们起初的位置偏差了。
而其它的操作符重载,几乎没有太大的差别,基本就围绕以上两种类型的改动,此处我们直接展示代码了:
template <class Iterator, class Ref, class Ptr>struct ReverseIterator{typedef ReverseIterator<Iterator, Ref, Ptr> self;Iterator _cur;ReverseIterator(Iterator it):_cur(it){}Ref operator*(){Iterator tmp = _cur;--tmp;return *tmp;}Ptr operator->(){Iterator tmp = _cur;--tmp;return &tmp->_data;}self& operator++(){--_cur;return *this;}self& operator++(int){self tmp(*this);--_cur;return tmp;}self& operator--(){++_cur;return *this;}self& operator--(int){self tmp(*this);++_cur;return tmp;}bool operator!=(const self& s){return _cur != s._cur;}bool operator==(const self& s){return _cur == s._cur;}};
这个反向迭代器的实现,可以作用于任何正向迭代器,也就是说,不论是list
,vector
等等各种容器,都可以使用这一套反向迭代器来封装原本的迭代器,从而获得反向迭代器,
相关文章:
C++:迭代器的封装思想
C:迭代器的封装思想 list迭代器实现反向迭代器实现 本博客将通过实现list的迭代器,以及它的反向迭代器,来帮助大家理解迭代器的底层逻辑,以及封装思想。 list迭代器实现 迭代器是一个遍历容器的工具,其可以通过自增自…...
飞天使-k8s知识点17-kubernetes实操2-pod探针的使用
文章目录 探针的使用容器探针启动实验1-启动探针的使用-startupprobeLiveness Probes 和 Readiness Probes演示若存在started.html 则进行 探针的使用 kubectl edit deploy -n kube-system corednslivenessprobe 的使用 livenessProbe:failureThreshold: 5httpGet:path: /heal…...
tee漏洞学习-翻译-3:TrustZone exploit for MSM8974
原文:http://bits-please.blogspot.com/2015/08/full-trustzone-exploit-for-msm8974.html 在这篇博文中,我们将介绍利用上一篇文章中描述的 TrustZone 漏洞的完整过程。 在开发此漏洞时,我只使用了我值得信赖的(个人࿰…...
rust递归遍历磁盘目录及文件
Std库实现 //遍历dir目录,找出修改日期距离当前超过age天的文件名称,存入file_list中 fn visit_dir(dir: &Path, file_list: &mut Vec<String>, age: u64) -> io::Result<()> {if dir.is_dir() {for entry in fs::read_dir(dir)…...
C语言每日一题(56)平衡二叉树
力扣网 110 平衡二叉树 题目描述 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 示例 1: 输入:root [3,9,20,…...
Flutter Android开发 梳理Google Material Design颜色体系
前言 做安卓开发(Kotlin语言),Flutter开发的人员应该都听说过谷歌一直推崇的Material Design,而Material Design Color是其推崇的颜色体系,具体来说,Material Design Color是一套旨在帮助设计师和开发者创…...
每日五道java面试题之java基础篇(六)
目录: 第一题:Java 创建对象有哪⼏种⽅式?第二题 .Integer a 127,Integer b 127;Integer c 128,Integer d 128;相等吗?第三题.Object 类的常⻅⽅法?第四题 List和Set的区别第五题 ArrayList和…...
c++ STL系列——(五)map
目录 引言 特点 包含头文件 基本特性 基本操作 插入元素 访问元素 移除元素 检查是否包含某个键 获取元素数量 高级特性 迭代器 自定义比较函数 实际应用 统计字符出现次数 缓存最近访问的元素 总结 引言 在C中,标准模板库(STL…...
Huggingface 文档翻译完毕
Accelerate 0.27 中文文档音频课程文档AutoTrain 中文文档AWS 中文文档竞赛中文文档Diffusers 0.26 中文文档深度强化学习课程文档数据集服务器中文文档Datasets 2.17 中文文档 Evaluate 0.4 中文文档Huggingface.js 中文文档Hub 中文文档Hub 客户端库 JS 0.20 中文文档推理 AP…...
C++中类的6个默认成员函数 【拷贝构造函数】
文章目录 拷贝构造函数的使用拷贝构造对于自定义类型【浅拷贝】深拷贝拷贝构造函数典型调用场景 拷贝构造函数的使用 在前几章学习对象的时候,我们有的时候需要一个与已存在对象一某一样的新对象 那在创建对象时,可否创建一个与已存在对象一某一样的新对…...
【前端高频面试题--Vuex下篇】
🚀 作者 :“码上有前” 🚀 文章简介 :前端高频面试题 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬前端高频面试题--Vuex篇 往期精彩内容Vuex 的原理Vuex中action和mutation的区别Vuex 和 localStor…...
MySQL性能调优篇(4)-查询语句的优化与重构
MySQL数据库查询语句的优化与重构 MySQL是一种常用的关系型数据库管理系统,广泛应用于Web开发中。在实际应用中,对数据库查询语句的优化和重构是提高应用性能和响应速度的重要手段。本文将介绍一些常见的优化技巧和重构方法,帮助开发者提高数…...
LInux、源码编译安装
步骤: 步骤1:安装开发工具gcc与make,释放源代码至指定目录 yum -y install gcc make 步骤2:tar解包,释放源代码至指定目录 tar -xf /root/tools.tar.gz -C /usr/local 步骤3:./configure 配置,…...
wordpress好的网站主题
有什么好的网站主题,都分享在这里了。 蓝色风格的wordpress模板,好的wordpress网站主题,需要既好看,又好用。 https://www.zhanyes.com/qiye/6305.html 血红色的好看的wordpress主题,布局经典,设计好的&am…...
【Java多线程】对进程与线程的理解
目录 1、进程/任务(Process/Task) 2、进程控制块抽象(PCB Process Control Block) 2.1、PCB重要属性 2.2、PCB中支持进程调度的一些属性 3、 内存分配 —— 内存管理(Memory Manage) 4、线程(Thread)…...
C# CAD交互界面-自定义面板集-查找定位(六)
运行环境 vs2022 c# cad2016 调试成功 一、代码说明 1. 类成员变量声明: List<ObjectId> objectIds new List<ObjectId>(); // 用于存储AutoCAD实体对象的ObjectId列表 private static Autodesk.AutoCAD.Windows.PaletteSet _ps2; // 自定义浮动面板…...
5.7 BCC工具之disksnoop.py解读
一,disksnoop.py简介 disksnoop工具用于追踪块设备的I/O操作的延迟,它会在每次I/O执行完成后打印一行摘要信息。我们根据这些摘要日志,来分析当前的I/O操作是否存在延迟,以判断I/O是否达到了瓶颈。 二,代码示例 #!/usr/bin/python # # disksnoop.py Trace block device…...
QT:实现图片选择器
一、效果图 二、用到的类 qApp:可以快速获取到项目目录位置。 QSettings :编写config文件,记录上次打开图片的位置,下次打开图片会从上次的位置查找图片。 QPixmap:用于图片的缩放,防止图片过小࿰…...
LLM大模型相关问题汇总---包括问题与答案
一、基础篇 1. 目前主流的开源模型体系有哪些? - Transformer体系:由Google提出的Transformer模型及其变体,如BERT、GPT等。 - PyTorch Lightning:一个基于PyTorch的轻量级深度学习框架,用于快速原型设计和实验…...
自动化测试定位不到元素怎么办?
1.动态id定位不到元素 分析原因:每次打开页面,ID都会变化。用ID去找元素,每次刷新页面ID都会发生变化。 解决方案:推荐使用xpath的相对路径方法或者cssSelector查找到该元素。 2.iframe原因定位不到元素 分析原因:…...
1 scala集合-数组
1 定长数组 定长数组,是指数组长度不可变。定义定长数组的方法有如下两种: 方法1: var/val variable_name new Array[元素类型](数组长度) // 通过制定长度定义例如,定义一个长度为20的Int 类型数组。 scala> val a new …...
双场板功率GaN HEMT电容模型以精确模拟开关行为
标题:Capacitance Modeling in Dual Field-Plate Power GaN HEMT for Accurate Switching Behavior(TED.16年) 摘要 本文提出了一种基于表面电位的紧凑模型,用于模拟具有栅极和源极场板(FP)结构的AlGaN/G…...
OpenCV Mat实例详解 四
OpenCV Mat实例详解三中详细介绍来了OpenCV Mat类的公有静态成员函数,下面介绍OpenCV Mat类的其他常用成员函数。 OpenCV Mat类常用成员函数 Mat & adjustROI (int dtop, int dbottom, int dleft, int dright); dtop ROI 上边界移动值,如…...
Fluke ADPT 连接器新增对福禄克万用 Fluke 106 的支持
所需设备: 1、Fluke ADPT连接器; 2、Fluke 106; Fluke 106 拆机图: 显示界面如下图: 并且可以将波形导出到EXCEL: 福禄克万用表需要自己动手改造!!!...
算法-3-基本的数据结构
单双链表 1.单链表双链表如何反转 import java.util.ArrayList; import java.util.List;public class Code01_ReverseList {public static class Node {public int value;public Node next;public Node(int data) {value data;}}public static class DoubleNode {public int…...
探秘Java反射:灵活编程的利器
前言 大家好,我是chowley,不知道大家在学习Java的过程中有没有听过反射的概念,今天我来总结一下我心中的Java反射。 在Java编程中,反射是一种强大的工具,它允许程序在运行时检查和操作类、方法、属性等,而…...
记录 | ubuntu pyqt5 pycharm配置
Ubuntu16.04pycharmpyqt5安装与配置_ubuntu pycharm pyqt5-CSDN博客pycharm激活码 6ZUMD7WWWU-eyJsaWNlbnNlSWQiOiI2WlVNRDdXV1dVIiwibGljZW5zZWVOYW1lIjoiSmV0cyBHcm91cCIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN…...
ESP32学习(1)——环境搭建
使用的ESP32板子如下图所示 它可以用Arduino 软件,基于C语言开发。但是,在这里,我是用Thonny软件,基于micro_python对其进行开发。 1.安装Thonny Thonny的软件安装包,可以去它官网上下载。Thonny, Python IDE for begi…...
Attention Is All Your Need论文笔记
论文解决了什么问题? 提出了一个新的简单网络架构——transformer,仅仅是基于注意力机制,完全免去递推和卷积,使得神经网络训练地速度极大地提高。 We propose a new simple network architecture, the Transformer, based sole…...
vue-进阶语法(四)
目录 v-model原理 v-model应用于组件 sync修饰符 ref 和 $refs(重点) $nextTick v-model原理 原理:v-model本质上是一个语法糖。例如应用在输入框上,就是 value属性 和 input事件 的合写。 作用:提供数据的双向…...
CGAL::2D Arrangements-7
7 几何Traits 几何Traits封装了几何实体的定义以及处理这些几何实体的几何predicates和构造的实现,供Arrangement_on_surface_2类模板和其他周边模块使用。应用于Arrangement的各种算法所确定的最小要求被组织在精细几何特征概念的层次中。每个概念列出的需求只包括…...
linux系统下vscode portable版本的rust环境搭建004:rust
目的:希望在获得一个新的系统之后,以最简便快速的方式搭配一个rust的编程环境命令在线安装只执行这句就行了 :curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh,因为是要portable安装所以按照以下的方式执行。 下载…...
从汇编角度解释线程间互斥-mutex互斥锁与lock_guard的使用
多线程并发的竞态问题 我们创建三个线程同时进行购票,代码如下 #include<iostream> #include<thread> #include<list> using namespace std; //总票数 int ticketCount100; //售票线程 void sellTicket(int idx) {while(ticketCount>0){cou…...
高程 | 多态性(c++)
文章目录 📚多态📚运算符重载🐇定义🐇规则🐇友元运算符重载函数🐇成员运算符重载函数 📚虚函数📚纯虚函数和抽象类 📚多态 多态:同样的消息被不同类型的对象…...
LV.23 D2 开发环境搭建及平台介绍 学习笔记
一、Keil MDK-ARM简介及安装 Keil MDK,也称MDK-ARM,Realview MDK (Microcontroller Development Kit)等。目前Keil MDK 由三家国内代理商提供技术支持和相关服务。 MDK-ARM软件为基于Cortex-M、Cortex-R4、ARM7、ARM9处理器设备…...
[uniapp生命周期]详细讲解uniapp中那些属于vue生命周期,那些属于uniapp独有的生命周期,以及这中间的区别 相关的内容和api 代码注释
目录 1. Vue.js生命周期函数2.Vue生命周期函数代码beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestroydestroyed$nextTick$forceUpdate$destroy 3. UniApp独有的生命周期函数onLaunchonShowonHideonError 4.总结 在UniApp中,除了Vue.js的生命周…...
【动态规划】【记忆化搜索】【状态压缩】1681. 最小不兼容性
作者推荐 【数位dp】【动态规划】【状态压缩】【推荐】1012. 至少有 1 位重复的数字 本文涉及知识点 动态规划汇总 状态压缩 记忆化搜索 1681. 最小不兼容性 给你一个整数数组 nums 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一…...
JVM-类加载器 双亲委派机制
申明:文章内容是本人学习极客时间课程所写,文字和图片基本来源于课程资料,在某些地方会插入一点自己的理解,未用于商业用途,侵删。 什么是JVM JVM是Java Virtual Machine(Java虚拟机)的缩写&a…...
vue axios 请求后端无法传参问题
vue请求后端无法传参问题 问题描述处理过程总结 问题描述 在学习vue时,使用axios调用后端,发现无法把参数正确传到后端,现象如下: 使用vue发起请求,浏览器上已经有传参,但是后端没接收到对应的用户名密码&…...
打印最小公倍数
打印最小公倍数 题目描述: 输入2个整数m和n,计算m和n的最小公倍数,并打印出结果 测试1: 输入:18 24 输出:72 测试2: 输入:18 6 输出:18解法思路: 最小公倍数是指两个…...
[AIGC] Java 和 Kotlin 的区别
好的,我还是以“萌萌哒小码农”的身份继续回答您的问题。 Java 和 Kotlin 是两种不同的编程语言,它们有许多共同点,但也有一些重要的区别。以下是一些常见的 Java 和 Kotlin 的区别: 语法 Kotlin 的语法比 Java 简洁得多&#…...
蓝桥杯电子类单片机提升一——超声波测距
前言 单片机资源数据包_2023 一、超声波测距原理 二、超声波测距的应用 1.超声波的发射 2.单片机知识补充:定时器 3.超声波的接收与计时 4.距离的计算 1)定时器1为16位自动重载+1T11.0592MHz 2)定时器1为16位自动重载&am…...
前端架构: 脚手架开发流程中的难点梳理
脚手架的开发流程 1 )开发流程 创建 npm 项目创建脚手架入口文件,最上方添加: #!/usr/bin/env node 配置 package.json, 添加 bin 属性编写脚手架代码将脚手架发布到 npm 2 )使用流程 安装脚手架 npm install -g your-own-cli …...
django中配置使用websocket
Django 默认情况下并不支持 WebSocket,但你可以通过集成第三方库如 channels 来实现 WebSocket 功能。channels 是一个 Django 应用,它提供了对 WebSocket、HTTP2 和其他协议的支持。 下面是如何在 Django 项目中使用 WebSocket 的基本步骤:…...
Rust复合类型详解
在Rust中,复合类型是一种能够将多个值组合在一起的数据类型。本篇博客将介绍两种常见的复合类型:元组(Tuple)和数组(Array)。 Tuple(元组) 元组是Rust中的一种复合类型,…...
学习 JavaScript 闭包
1. 前言 闭包是 JavaScript 中一种非常重要的概念,它允许函数访问其外部作用域中的变量,即使在函数被返回或者在其原始定义的作用域之外执行时仍然可以访问这些变量。 在讲解闭包之前我们得弄清楚下面的概念: 作用域链: JavaSc…...
VScode中配置 C/C++ 环境 | IT拯救者
文章目录 0 引言1. 下载编辑器VScode2. 下载编译器MinGW并解压3. 将MinGW添加至环境变量4. 配置VScode插件5. 运行代码6. 调整和优化7. 提示8. 例行格式条款9. 例行格式条款 0 引言 由于VScode毛毛张使用不习惯,因此配置教程记不住,不过毛毛张看到一篇不…...
基于Python实现Midjourney集成到(个人/公司)平台中
目前Midjourney没有对外开放Api,想体验他们的服务只能在discord中进入他们的频道进行体验或者把他们的机器人拉入自己创建的服务器中;而且现在免费的也用不了了,想使用就得订阅。本教程使用midjourney-api这个开源项目,搭建Midjou…...
蓝桥杯刷题--python-6
0最大距离 - 蓝桥云课 (lanqiao.cn) n=int(input()) nums=list(map(int,input().split()))max_=float(-inf) for i in range (n):for j in range (i+1,n):tmp=abs(i-j)+abs(nums[i]-nums[j])max_=max(tmp,max_) print(max_) 0最长递增 - 蓝桥云课 (lanqiao.cn) import os im…...
node+vue3+mysql前后分离开发范式——实现对数据库表的增删改查
文章目录 ⭐前言⭐ 功能设计与实现💖 node后端操作数据库实现增删改查💖 vue3前端实现增删改查⭐ 效果⭐ 总结⭐ 结束⭐结束⭐前言 大家好,我是yma16,本文分享关于 node+vue3+mysql前后分离开发范式——实现对数据库表的增删改查。 技术选型 前端:vite+vue3+antd 后端:…...