HarmonyOS NEXT应用开发之ForEach:循环渲染

ForEach接口基于数组类型数据来进行循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在ForEach父容器组件中的子组件。例如,ListItem组件要求ForEach的父容器组件必须为 List组件 。

说明:
从API version 9开始,该接口支持在ArkTS卡片中使用。

接口描述

ForEach(arr: Array,itemGenerator: (item: any, index: number) => void,keyGenerator?: (item: any, index: number) => string
)

以下是参数的详细说明:

参数名参数类型是否必填参数描述
arrArray数据源,为Array类型的数组。
说明:
- 可以设置为空数组,此时不会创建子组件。
- 可以设置返回值为数组类型的函数,例如arr.slice(1, 3),但设置的函数不应改变包括数组本身在内的任何状态变量,例如不应使用Array.splice(),Array.sort()Array.reverse()这些会改变原数组的函数。
itemGenerator(item: any, index: number) => void组件生成函数。
- 为数组中的每个元素创建对应的组件。
- item参数:arr数组中的数据项。
- index参数(可选):arr数组中的数据项索引。
说明:
- 组件的类型必须是ForEach的父容器所允许的。例如,ListItem组件要求ForEach的父容器组件必须为List组件。
keyGenerator(item: any, index: number) => string键值生成函数。
- 为数据源arr的每个数组项生成唯一且持久的键值。函数返回值为开发者自定义的键值生成规则。
- item参数:arr数组中的数据项。
- index参数(可选):arr数组中的数据项索引。
说明:
- 如果函数缺省,框架默认的键值生成函数为(item: T, index: number) => { return index + '__' + JSON.stringify(item); }
- 键值生成函数不应改变任何组件状态。

说明:

  • ForEachitemGenerator函数可以包含if/else条件渲染逻辑。另外,也可以在if/else条件渲染语句中使用ForEach组件。
  • 在初始化渲染时,ForEach会加载数据源的所有数据,并为每个数据项创建对应的组件,然后将其挂载到渲染树上。如果数据源非常大或有特定的性能需求,建议使用LazyForEach组件。

键值生成规则

ForEach循环渲染过程中,系统会为每个数组元素生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。

ForEach提供了一个名为keyGenerator的参数,这是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有定义keyGenerator函数,则ArkUI框架会使用默认的键值生成函数,即(item: any, index: number) => { return index + '__' + JSON.stringify(item); }

ArkUI框架对于ForEach的键值生成有一套特定的判断规则,这主要与itemGenerator函数的第二个参数index以及keyGenerator函数的第二个参数index有关,具体的键值生成规则判断逻辑如下图所示。

图1 ForEach键值生成规则

说明:
ArkUI框架会对重复的键值发出警告。在UI更新的场景下,如果出现重复的键值,框架可能无法正常工作。

组件创建规则

在确定键值生成规则后,ForEach的第二个参数itemGenerator函数会根据键值生成规则为数据源的每个数组项创建组件。组件的创建包括两种情况: ForEach首次渲染 和 ForEach非首次渲染 。

首次渲染

在ForEach首次渲染时,会根据前述键值生成规则为数据源的每个数组项生成唯一键值,并创建相应的组件。

@Entry
@Component
struct Parent {@State simpleList: Array<string> = ['one', 'two', 'three'];build() {Row() {Column() {ForEach(this.simpleList, (item: string) => {ChildItem({ item: item })}, (item: string) => item)}.width('100%').height('100%')}.height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ChildItem {@Prop item: string;build() {Text(this.item).fontSize(50)}
}

运行效果如下图所示。

图2 ForEach数据源不存在相同值案例首次渲染运行效果图

在上述代码中,键值生成规则是keyGenerator函数的返回值item。在ForEach渲染循环时,为数据源数组项依次生成键值onetwothree,并创建对应的ChildItem组件渲染到界面上。

当不同数组项按照键值生成规则生成的键值相同时,框架的行为是未定义的。例如,在以下代码中,ForEach渲染相同的数据项two时,只创建了一个ChildItem组件,而没有创建多个具有相同键值的组件。

@Entry
@Component
struct Parent {@State simpleList: Array<string> = ['one', 'two', 'two', 'three'];build() {Row() {Column() {ForEach(this.simpleList, (item: string) => {ChildItem({ item: item })}, (item: string) => item)}.width('100%').height('100%')}.height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ChildItem {@Prop item: string;build() {Text(this.item).fontSize(50)}
}

运行效果如下图所示。

图3 ForEach数据源存在相同值案例首次渲染运行效果图

在该示例中,最终键值生成规则为item。当ForEach遍历数据源simpleList,遍历到索引为1的two时,按照最终键值生成规则生成键值为two的组件并进行标记。当遍历到索引为2的two时,按照最终键值生成规则当前项的键值也为two,此时不再创建新的组件。

非首次渲染

在ForEach组件进行非首次渲染时,它会检查新生成的键值是否在上次渲染中已经存在。如果键值不存在,则会创建一个新的组件;如果键值存在,则不会创建新的组件,而是直接渲染该键值所对应的组件。例如,在以下的代码示例中,通过点击事件修改了数组的第三项值为"new three",这将触发ForEach组件进行非首次渲染。

@Entry
@Component
struct Parent {@State simpleList: Array<string> = ['one', 'two', 'three'];build() {Row() {Column() {Text('点击修改第3个数组项的值').fontSize(24).fontColor(Color.Red).onClick(() => {this.simpleList[2] = 'new three';})ForEach(this.simpleList, (item: string) => {ChildItem({ item: item }).margin({ top: 20 })}, (item: string) => item)}.justifyContent(FlexAlign.Center).width('100%').height('100%')}.height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ChildItem {@Prop item: string;build() {Text(this.item).fontSize(30)}
}

运行效果如下图所示。

图4 ForEach非首次渲染案例运行效果图

从本例可以看出@State 能够监听到简单数据类型数组数据源 simpleList 数组项的变化。

  1. simpleList 数组项发生变化时,会触发 ForEach 进行重新渲染。
  2. ForEach 遍历新的数据源 ['one', 'two', 'new three'],并生成对应的键值onetwonew three
  3. 其中,键值onetwo在上次渲染中已经存在,所以 ForEach 复用了对应的组件并进行了渲染。对于第三个数组项 “new three”,由于其通过键值生成规则 item 生成的键值new three在上次渲染中不存在,因此 ForEach 为该数组项创建了一个新的组件。

使用场景

ForEach组件在开发过程中的主要应用场景包括: 数据源不变 、 数据源数组项发生变化 (如插入、删除操作)、 数据源数组项子属性变化 。

数据源不变

在数据源保持不变的场景中,数据源可以直接采用基本数据类型。例如,在页面加载状态时,可以使用骨架屏列表进行渲染展示。

@Entry
@Component
struct ArticleList {@State simpleList: Array<number> = [1, 2, 3, 4, 5];build() {Column() {ForEach(this.simpleList, (item: string) => {ArticleSkeletonView().margin({ top: 20 })}, (item: string) => item)}.padding(20).width('100%').height('100%')}
}@Builder
function textArea(width: number | Resource | string = '100%', height: number | Resource | string = '100%') {Row().width(width).height(height).backgroundColor('#FFF2F3F4')
}@Component
struct ArticleSkeletonView {build() {Row() {Column() {textArea(80, 80)}.margin({ right: 20 })Column() {textArea('60%', 20)textArea('50%', 20)}.alignItems(HorizontalAlign.Start).justifyContent(FlexAlign.SpaceAround).height('100%')}.padding(20).borderRadius(12).backgroundColor('#FFECECEC').height(120).width('100%').justifyContent(FlexAlign.SpaceBetween)}
}

运行效果如下图所示。

图5 骨架屏运行效果图

在本示例中,采用数据项item作为键值生成规则,由于数据源simpleList的数组项各不相同,因此能够保证键值的唯一性。

数据源数组项发生变化

在数据源数组项发生变化的场景下,例如进行数组插入、删除操作或者数组项索引位置发生交换时,数据源应为对象数组类型,并使用对象的唯一ID作为最终键值。例如,当在页面上通过手势上滑加载下一页数据时,会在数据源数组尾部新增新获取的数据项,从而使得数据源数组长度增大。

class Article {id: string;title: string;brief: string;constructor(id: string, title: string, brief: string) {this.id = id;this.title = title;this.brief = brief;}
}@Entry
@Component
struct ArticleListView {@State isListReachEnd: boolean = false;@State articleList: Array<Article> = [new Article('001', '第1篇文章', '文章简介内容'),new Article('002', '第2篇文章', '文章简介内容'),new Article('003', '第3篇文章', '文章简介内容'),new Article('004', '第4篇文章', '文章简介内容'),new Article('005', '第5篇文章', '文章简介内容'),new Article('006', '第6篇文章', '文章简介内容')]loadMoreArticles() {this.articleList.push(new Article('007', '加载的新文章', '文章简介内容'));}build() {Column({ space: 5 }) {List() {ForEach(this.articleList, (item: Article) => {ListItem() {ArticleCard({ article: item }).margin({ top: 20 })}}, (item: Article) => item.id)}.onReachEnd(() => {this.isListReachEnd = true;}).parallelGesture(PanGesture({ direction: PanDirection.Up, distance: 80 }).onActionStart(() => {if (this.isListReachEnd) {this.loadMoreArticles();this.isListReachEnd = false;}})).padding(20).scrollBar(BarState.Off)}.width('100%').height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ArticleCard {@Prop article: Article;build() {Row() {Image($r('app.media.icon')).width(80).height(80).margin({ right: 20 })Column() {Text(this.article.title).fontSize(20).margin({ bottom: 8 })Text(this.article.brief).fontSize(16).fontColor(Color.Gray).margin({ bottom: 8 })}.alignItems(HorizontalAlign.Start).width('80%').height('100%')}.padding(20).borderRadius(12).backgroundColor('#FFECECEC').height(120).width('100%').justifyContent(FlexAlign.SpaceBetween)}
}

初始运行效果(左图)和手势上滑加载后效果(右图)如下图所示。

图6 数据源数组项变化案例运行效果图

在本示例中,ArticleCard组件作为ArticleListView组件的子组件,通过@Prop装饰器接收一个Article对象,用于渲染文章卡片。

  1. 当列表滚动到底部时,如果手势滑动距离超过指定的80,将触发loadMoreArticle()函数。此函数会在articleList数据源的尾部添加一个新的数据项,从而增加数据源的长度。
  2. 数据源被@State装饰器修饰,ArkUI框架能够感知到数据源长度的变化,并触发ForEach进行重新渲染。

数据源数组项子属性变化

当数据源的数组项为对象数据类型,并且只修改某个数组项的属性值时,由于数据源为复杂数据类型,ArkUI框架无法监听到@State装饰器修饰的数据源数组项的属性变化,从而无法触发ForEach的重新渲染。为实现ForEach重新渲染,需要结合@Observed@ObjectLink装饰器使用。例如,在文章列表卡片上点击“点赞”按钮,从而修改文章的点赞数量。

@Observed
class Article {id: string;title: string;brief: string;isLiked: boolean;likesCount: number;constructor(id: string, title: string, brief: string, isLiked: boolean, likesCount: number) {this.id = id;this.title = title;this.brief = brief;this.isLiked = isLiked;this.likesCount = likesCount;}
}@Entry
@Component
struct ArticleListView {@State articleList: Array<Article> = [new Article('001', '第0篇文章', '文章简介内容', false, 100),new Article('002', '第1篇文章', '文章简介内容', false, 100),new Article('003', '第2篇文章', '文章简介内容', false, 100),new Article('004', '第4篇文章', '文章简介内容', false, 100),new Article('005', '第5篇文章', '文章简介内容', false, 100),new Article('006', '第6篇文章', '文章简介内容', false, 100),];build() {List() {ForEach(this.articleList, (item: Article) => {ListItem() {ArticleCard({article: item}).margin({ top: 20 })}}, (item: Article) => item.id)}.padding(20).scrollBar(BarState.Off).backgroundColor(0xF1F3F5)}
}@Component
struct ArticleCard {@ObjectLink article: Article;handleLiked() {this.article.isLiked = !this.article.isLiked;this.article.likesCount = this.article.isLiked ? this.article.likesCount + 1 : this.article.likesCount - 1;}build() {Row() {Image($r('app.media.icon')).width(80).height(80).margin({ right: 20 })Column() {Text(this.article.title).fontSize(20).margin({ bottom: 8 })Text(this.article.brief).fontSize(16).fontColor(Color.Gray).margin({ bottom: 8 })Row() {Image(this.article.isLiked ? $r('app.media.iconLiked') : $r('app.media.iconUnLiked')).width(24).height(24).margin({ right: 8 })Text(this.article.likesCount.toString()).fontSize(16)}.onClick(() => this.handleLiked()).justifyContent(FlexAlign.Center)}.alignItems(HorizontalAlign.Start).width('80%').height('100%')}.padding(20).borderRadius(12).backgroundColor('#FFECECEC').height(120).width('100%').justifyContent(FlexAlign.SpaceBetween)}
}

上述代码的初始运行效果(左图)和点击第1个文章卡片上的点赞图标后的运行效果(右图)如下图所示。

图7 数据源数组项子属性变化案例运行效果图

在本示例中,Article类被@Observed装饰器修饰。父组件ArticleListView传入Article对象实例给子组件ArticleCard,子组件使用@ObjectLink装饰器接收该实例。

  1. 当点击第1个文章卡片上的点赞图标时,会触发ArticleCard组件的handleLiked函数。该函数修改第1个卡片对应组件里article实例的isLikedlikesCount属性值。
  2. 由于子组件ArticleCard中的article使用了@ObjectLink装饰器,父子组件共享同一份article数据。因此,父组件中articleList的第1个数组项的isLikedlikedCounts数值也会同步修改。
  3. 当父组件监听到数据源数组项属性值变化时,会触发ForEach重新渲染。
  4. 在此处,ForEach键值生成规则为数组项的id属性值。当ForEach遍历新数据源时,数组项的id均没有变化,不会新建组件。
  5. 渲染第1个数组项对应的ArticleCard组件时,读取到的isLikedlikesCount为修改后的新值。

使用建议

  • 尽量避免在最终的键值生成规则中包含数据项索引index,以防止出现渲染结果非预期和渲染性能降低。如果业务确实需要使用index,例如列表需要通过index进行条件渲染,开发者需要接受ForEach在改变数据源后重新创建组件所带来的性能损耗。
  • 为满足键值的唯一性,对于对象数据类型,建议使用对象数据中的唯一id作为键值。
  • 基本数据类型的数据项没有唯一ID属性。如果使用基本数据类型本身作为键值,必须确保数组项无重复。因此,对于数据源会发生变化的场景,建议将基本数据类型数组转化为具备唯一ID属性的对象数据类型数组,再使用ID属性作为键值生成规则。

不推荐案例

开发者在使用ForEach的过程中,若对于键值生成规则的理解不够充分,可能会出现错误的使用方式。错误使用一方面会导致功能层面问题,例如 渲染结果非预期 ,另一方面会导致性能层面问题,例如 渲染性能降低。

渲染结果非预期

在本示例中,通过设置ForEach的第三个参数KeyGenerator函数,自定义键值生成规则为数据源的索引index的字符串类型值。当点击父组件Parent中“在第1项后插入新项”文本组件后,界面会出现非预期的结果。

@Entry
@Component
struct Parent {@State simpleList: Array<string> = ['one', 'two', 'three'];build() {Column() {Button() {Text('在第1项后插入新项').fontSize(30)}.onClick(() => {this.simpleList.splice(1, 0, 'new item');})ForEach(this.simpleList, (item: string) => {ChildItem({ item: item })}, (item: string, index: number) => index.toString())}.justifyContent(FlexAlign.Center).width('100%').height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ChildItem {@Prop item: string;build() {Text(this.item).fontSize(30)}
}

上述代码的初始渲染效果(左图)和点击“在第1项后插入新项”文本组件后的渲染效果(右图)如下图所示。

图8 渲染结果非预期运行效果图

ForEach在首次渲染时,创建的键值依次为"0"、“1”、“2”。

插入新项后,数据源simpleList变为['one', 'new item', 'two', 'three'],框架监听到@State装饰的数据源长度变化触发ForEach重新渲染。

ForEach依次遍历新数据源,遍历数据项"one"时生成键值"0",存在相同键值,因此不创建新组件。继续遍历数据项"new item"时生成键值"1",存在相同键值,因此不创建新组件。继续遍历数据项"two"生成键值"2",存在相同键值,因此不创建新组件。最后遍历数据项"three"时生成键值"3",不存在相同键值,创建内容为"three"的新组件并渲染。

从以上可以看出,当最终键值生成规则包含index时,期望的界面渲染结果为['one', 'new item', 'two', 'three'],而实际的渲染结果为['one', 'two', 'three', 'three'],渲染结果不符合开发者预期。因此,开发者在使用ForEach时应尽量避免最终键值生成规则中包含index

渲染性能降低

在本示例中,ForEach的第三个参数KeyGenerator函数处于缺省状态。根据上述 键值生成规则 ,此例使用框架默认的键值生成规则,即最终键值为字符串index + '__' + JSON.stringify(item)。当点击“在第1项后插入新项”文本组件后,ForEach将需要为第2个数组项以及其后的所有项重新创建组件。

@Entry
@Component
struct Parent {@State simpleList: Array<string> = ['one', 'two', 'three'];build() {Column() {Button() {Text('在第1项后插入新项').fontSize(30)}.onClick(() => {this.simpleList.splice(1, 0, 'new item');console.log(`[onClick]: simpleList is ${JSON.stringify(this.simpleList)}`);})ForEach(this.simpleList, (item: string) => {ChildItem({ item: item })})}.justifyContent(FlexAlign.Center).width('100%').height('100%').backgroundColor(0xF1F3F5)}
}@Component
struct ChildItem {@Prop item: string;aboutToAppear() {console.log(`[aboutToAppear]: item is ${this.item}`);}build() {Text(this.item).fontSize(50)}
}

以上代码的初始渲染效果(左图)和点击"在第1项后插入新项"文本组件后的渲染效果(右图)如下所示。

图9 渲染性能降低案例运行效果图

点击“在第1项后插入新项”文本组件后,IDE的日志打印结果如下所示。

图10 渲染性能降低案例日志打印图

插入新项后,ForEachnew itemtwothree三个数组项创建了对应的组件ChildItem,并执行了组件的 aboutToAppear() 生命周期函数。这是因为:

  1. ForEach首次渲染时,创建的键值依次为0__one1__two2__three
  2. 插入新项后,数据源simpleList变为['one', 'new item', 'two', 'three'],ArkUI框架监听到@State装饰的数据源长度变化触发ForEach重新渲染。
  3. ForEach依次遍历新数据源,遍历数据项one时生成键值0__one,键值已存在,因此不创建新组件。继续遍历数据项new item时生成键值1__new item,不存在相同键值,创建内容为new item的新组件并渲染。继续遍历数据项two生成键值2__two,不存在相同键值,创建内容为two的新组件并渲染。最后遍历数据项three时生成键值3__three,不存在相同键值,创建内容为three的新组件并渲染。

尽管此示例中界面渲染的结果符合预期,但每次插入一条新数组项时,ForEach都会为从该数组项起后面的所有数组项全部重新创建组件。当数据源数据量较大或组件结构复杂时,由于组件无法得到复用,将导致性能体验不佳。因此,除非必要,否则不推荐将第三个参数KeyGenerator函数处于缺省状态,以及在键值生成规则中包含数据项索引index
为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

![](ht
tps://img-blog.csdnimg.cn/img_convert/c02d1bcf9201e3d3d8baf3b812f8e370.webp?x-oss-process=image/format,png)

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

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

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

相关文章

环形链表的约瑟夫问题

著名的 Josephus 问题&#xff1a; 据说著名犹太历史学家Josephus&#xff08;弗拉维奥约瑟夫斯&#xff09;有过以下的故事&#xff1a;在罗马人占领乔塔帕特后&#xff0c;39 个犹太人与Josephus及他的朋友躲到一个洞中&#xff0c;39个犹太人决定宁愿死也不要被敌人抓到&…

【哈希表专题】(1. 两数之和 面试题 01.02. 判定是否互为字符重排 217. 存在重复元素 219. 存在重复元素 II 49. 字母异位词分组)

文章目录 哈希表1. 两数之和面试题 01.02. 判定是否互为字符重排217. 存在重复元素219. 存在重复元素 II49. 字母异位词分组 哈希表 哈希表是什么&#xff1a;存储数据的容器 作用&#xff1a;快速查找某个元素。O(1) 当我们需要频繁的查找某一个数的时候&#xff0c;可以使…

图像拼接——最小割准则提取拼接缝

一、最大流问题与Ford-Fulkerson算法介绍 二、最大流与最小割 显然,我们有对任意一个割,穿过该割的净流量上界就是该割的容量,即不可能超过割的容量。所以网络的最大流必然无法超过网络的最小割。最小割是指割的容量最小,最大流是指网络当中最大的净流量,简单的例子s是水龙…

【蓝桥备赛】异或和——树状数组、DFS

题目链接 异或和 思路分析 树上每个点都有一个点权&#xff0c;对树上的更新操作是修改指定点的点权&#xff0c;查询操作是查询指定点为根结点的子树点权异或和。 这里的这些操作都和树状数组的单点修改和区间查询非常相似&#xff0c;即我们在修改一个点时&#xff0c;同时…

蓝桥杯真题:递增序列

import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改 public class Main {public static int is1(char ch[][],int m,int n){int ans0;for (int i0;i<m;i){for (int j0;j<n;j){int add1;while(jadd<n){if(ch[i][j]<ch[i][jadd]) ans; //横…

SAP新的扩展策略

在软件即服务&#xff08;SaaS&#xff09;应用的推动下&#xff0c;SAP Cloud优先的战略非常明显&#xff0c;随之带来的是SAP Clean core的战略&#xff0c;从经典的 ABAP 可扩展性模式转变为 SAP S/4HANA 现代可扩展性模式。那么Clean core战略到底是什么&#xff1f;新的扩…

基于向量数据库搭建自己的搜索引擎

前言【基于chatbot】 厌倦了商业搜索引擎搜索引擎没完没了的广告&#xff0c;很多时候&#xff0c;只是需要精准高效地检索信息&#xff0c;而不是和商业广告“斗智斗勇”。以前主要是借助爬虫工具&#xff0c;而随着技术的进步&#xff0c;现在有了更多更方便的解决方案&…

LongAdder 和 Striped64 基础学习

cs&#xff0c;表示 Cell 数组的引用&#xff1b;b&#xff0c;表示获取的 base 值&#xff0c;类似于 AtomicLong 中全局变量的 value 值&#xff0c;在没有竞争的情况下数据直接累加到 base 上&#xff0c;或者扩容时&#xff0c;也需要将数据写入到 base 上&#xff1b;v&am…

Linux第2课Windows下的环境配置-虚拟机安装

文章目录 Linux第2课Windows下的环境配置-虚拟机安装一、VMware虚拟机的安装&#xff08;一&#xff09;安装VMware&#xff08;二&#xff09;启动电脑本地的VMware相关服务 二、VirtualBox安装 Linux第2课Windows下的环境配置-虚拟机安装 本节课程提供了两种虚拟机的安装方法…

个人医疗开支预测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 项目背景 随着医疗成本的持续上涨&#xff0c;个人医疗开支成为一个重要议题。理解影响医疗费用的多种因素对于医疗保险公司、政府机构以及个人…

磁环的使用方法

磁环的使用方法 磁环的工作原理共模滤波用法差模滤波用法各种材料磁环的对应频率磁环的感量计算 磁环的工作原理 共模滤波用法 差模滤波用法 各种材料磁环的对应频率 磁环的感量计算

Redis从入门到精通(四)Redis实战(二)商户查询缓存

↑↑↑请在文章头部下载测试项目原代码↑↑↑ 文章目录 前言4.2 商户查询缓存4.2.1 缓存介绍4.2.2 查询商户信息的传统做法4.2.2.1 接口文档4.2.2.2 代码实现4.2.2.3 功能测试 4.2.3 查询商户信息添加Redis缓存4.2.3.1 逻辑分析4.2.3.2 代码实现4.2.3.3 功能测试 4.2.3 数据一致…

【MATLAB源码-第177期】基于matlab的蜘蛛蜂优化算法(SWO)无人机三维路径规划,输出做短路径图和适应度曲线

操作环境&#xff1a; MATLAB 2022a 1、算法描述 蜘蛛蜂优化算法&#xff08;Spider Wasp Optimization, SWO&#xff09;是一种启发式算法&#xff0c;它受到自然界中蜘蛛和蜂这两种生物的行为模式启发而开发。这一算法主要模拟了蜘蛛捕食与蜂群社会行为之间的相互作用&…

网络以太网之(1)基础概念

网络以太网之(1)基础概念 Author: Once Day Date: 2024年4月1日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day的…

C语言-----数据在内存中的存储(1)

1.整数在内存中的存储 我们之前就了解过整数的二进制写法分别有3种&#xff0c;分别为原码&#xff0c;反码&#xff0c;补码。整型在内存中存储的是补码。 原码&#xff0c;反码&#xff0c;补码都有自己的符号位和数值位&#xff0c;符号位为1时&#xff0c;则表示负数&…

【Docker笔记05】【网络模式】

一、前言 本系列是根据 B 站 尚硅谷 Docker 视频 学习记录笔记。因为没有视频课件&#xff0c;部分内容摘自 https://www.yuque.com/tmfl/cloud/dketq0。 本系列仅为自身学习笔记记录使用&#xff0c;记录存在偏差&#xff0c;推荐阅读原视频内容或本文参考笔记。 二、简单介…

通用开发技能系列:Authentication、OAuth、JWT 认证策略

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 通用开发技能系列 文章&#xff0c;主要对编程通用技能 Authentication、OAuth、JWT 认证策略 进行学习 1.Basic Authentication认证 每个请求都需要将 用户名密码 进行base64编码后&#xff0c;放在请求头的A…

基于隐私保护的可追踪可撤销密文策略属性加密方案论文阅读

论文是2022年发表的A Traceable and Revocable Ciphertext-Policy Attribute-based Encryption Scheme Based on Privacy Protection 摘要 本篇论文提出了一种具有用户撤销、白盒追踪、策略策略隐藏功能的CP-ABE方案。在该方案中密文被分为两个部分&#xff1a;第一个部分是和…

基于springboot实现教师人事档案管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现在线商城系统演示 摘要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本ONLY在线商城系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理…

第六期丨酷雷曼无人机技能培训

第6期无人机技能提升培训 盼望着盼望着&#xff0c;第六期无人机技能提升培训会终于如期和大家见面了。 2024年1月1日&#xff0c;国务院、中央军事委员会颁布《无人驾驶航空器飞行管理暂行条例》&#xff0c;对民用无人机飞行活动实施更为严格的规范约束&#xff0c;越来越多…