鸿蒙Harmony角落里的知识:从ECMA规范到ArkTS接口(一)

 前言:

在深入理解和使用ArkTS中的数组操作之前,我们有必要先了解ECMAScript(ECMA)规范中的规定。ECMA规范是JavaScript语言的官方标准,而ArkTS作为JavaScript的超集,也遵守了这些规定。本系列文章旨在探讨ECMA规范如何定义接口,以及如何在ArkTS该接口如何使用。

ECMA对typedArray.slice接口的定义

在ECMA规范中,typedArray 是一个泛型对象,表示一个固定长度的二进制数据缓冲区,并且可以用来创建多种类型的视图,比如 Uint8ArrayInt16ArrayFloat32Array 等。而其中的 .slice() 方法,用于浅复制 typedArray 的一部分到一个新的 typedArray 实例。

根据ECMAScript规范,typedArray.slice(begin, end) 方法接受两个参数:begin 表示起始位置,end 表示结束位置(不包含)。如果不提供 end 参数,slice 方法会复制从 begin 到原数组末尾的所有元素。如果 begin 或 end 是负数,则表示从数组末尾开始的偏移量。返回值是一个新的 typedArray 实例,包含指定范围的元素。

我们可以直接查看ECMA规范中对该函数的描述:

23.2.3.27 %TypedArray%.prototype.slice ( start, end )
The interpretation and use of the arguments of this method are the same as for Array.prototype.slice as defined in 23.1.3.28.This method performs the following steps when called:
1. Let O be the this value.
2. Perform ? ValidateTypedArray(O).
3. Let len be O.[[ArrayLength]].
4. Let relativeStart be ? ToIntegerOrInfinity(start).
5. If relativeStart = -∞, let k be 0.
6. Else if relativeStart < 0, let k be max(len + relativeStart, 0).
7. Else, let k be min(relativeStart, len).
8. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToIntegerOrInfinity(end).
9. If relativeEnd = -∞, let final be 0.
10. Else if relativeEnd < 0, let final be max(len + relativeEnd, 0).
11. Else, let final be min(relativeEnd, len).
12. Let count be max(final - k, 0).
13. Let A be ? TypedArraySpeciesCreate(O, « 𝔽(count) »).
14. If count > 0, thena. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.b. Let srcType be TypedArrayElementType(O).c. Let targetType be TypedArrayElementType(A).d. If srcType is targetType, theni. NOTE: The transfer must be performed in a manner that preserves the bit-level encoding of the source data.ii. Let srcBuffer be O.[[ViewedArrayBuffer]].iii. Let targetBuffer be A.[[ViewedArrayBuffer]].iv. Let elementSize be TypedArrayElementSize(O).v. Let srcByteOffset be O.[[ByteOffset]].vi. Let srcByteIndex be (k × elementSize) + srcByteOffset.vii. Let targetByteIndex be A.[[ByteOffset]].viii. Let limit be targetByteIndex + count × elementSize.ix. Repeat, while targetByteIndex < limit,1. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, Uint8, true, Unordered).2. Perform SetValueInBuffer(targetBuffer, targetByteIndex, Uint8, value, true, Unordered).3. Set srcByteIndex to srcByteIndex + 1.4. Set targetByteIndex to targetByteIndex + 1.e. Else,i. Let n be 0.ii. Repeat, while k < final,1.Let Pk be ! ToString(𝔽(k)).2.Let kValue be ! Get(O, Pk).3.Perform ! Set(A, ! ToString(𝔽(n)), kValue, true).4.Set k to k + 1.5.Set n to n + 1.
15. Return A.
This method is not generic. The this value must be an object with a [[TypedArrayName]] internal slot.

大家可以看到,ECMA规范中对接口的描述非常详细,对各种参数的输入和输出都做非常细致的说明,无论是符合标准的语言接口的实现,还是

ArkTS对slice的接口描述

在ArkTS中,接口(Interfaces)是一个非常强大的特性,允许开发者定义对象的类型。为了实现一个符合ECMA规范的 slice 方法,ArkTS对该方法的定义声明如下:

以\static_core\plugins\ets\stdlib\escompat\TypedUArrays.ets的Uint8Array定义为例:

/*** Creates a slice of current Uint8Array using range [begin, end)** @param begin start index to be taken into slice** @param end last index to be taken into slice** @returns a new Uint8Array with elements of current Uint8Array[begin;end) where end index is excluded** @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice*/public slice(begin?: Number, end?: Number): Uint8Array {return this.slice(asIntOrDefault(begin, 0 as int), asIntOrDefault(end, this.lengthInt))}/*** Creates a slice of current Uint8Array using range [begin, end)** @param begin start index to be taken into slice** @param end last index to be taken into slice** @returns a new Uint8Array with elements of current Uint8Array[begin;end) where end index is excluded** @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice*/public slice(begin: number, end: number): Uint8Array {return this.slice(begin as int, end as int)}/*** Creates a slice of current Uint8Array using range [begin, end)** @param begin start index to be taken into slice** @param end last index to be taken into slice** @returns a new Uint8Array with elements of current Uint8Array[begin;end) where end index is excluded** @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice*/public slice(begin: number, end: int): Uint8Array {return this.slice(begin as int, end as int)}/*** Creates a slice of current Uint8Array using range [begin, end)** @param begin start index to be taken into slice** @param end last index to be taken into slice** @returns a new Uint8Array with elements of current Uint8Array[begin;end) where end index is excluded** @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice*/public slice(begin: int, end: number): Uint8Array {return this.slice(begin as int, end as int)}/*** Creates a slice of current Uint8Array using range [begin, end)** @param begin start index to be taken into slice** @param end last index to be taken into slice** @returns a new Uint8Array with elements of current Uint8Array[begin;end) where end index is excluded** @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice*/public slice(begin: int, end: int): Uint8Array {const len: int = this.lengthIntconst relStart = normalizeIndex(begin, len)const relEnd = normalizeIndex(end, len)let count = relEnd - relStartif (count < 0) {count = 0}if (this.buffer instanceof ArrayBuffer) {let buf = (this.buffer as ArrayBuffer).slice(relStart * Uint8Array.BYTES_PER_ELEMENT as int, relEnd * Uint8Array.BYTES_PER_ELEMENT as int) as ArrayBufferreturn new Uint8Array(buf)} else if (this.buffer instanceof SharedArrayBuffer) {let buf = (this.buffer as SharedArrayBuffer).slice(relStart * Uint8Array.BYTES_PER_ELEMENT as int, relEnd * Uint8Array.BYTES_PER_ELEMENT as int) as SharedArrayBufferreturn new Uint8Array(buf)} else {throw new Error("unexpected type of buffer")}}/*** Creates a slice of current Uint8Array using range [begin, this.lengthInt).** @param begin start index to be taken into slice** @returns a new Uint8Array with elements of current Uint8Array[begin, this.lengthInt)*/public slice(begin: number): Uint8Array {return this.slice(begin as int)}/*** Creates a slice of current Uint8Array using range [begin, this.lengthInt).** @param begin start index to be taken into slice** @returns a new Uint8Array with elements of current Uint8Array[begin, this.lengthInt)*/public slice(begin: int): Uint8Array {return this.slice(begin, this.lengthInt)}

在这个例子中,我们创建了一个 Int32ArrayWithSlice 类,它实现了 TypedArray 接口,包含了符合ECMA规范的 slice 方法。这个方法返回的是 Int32ArrayWithSlice 的新实例,包含了切片后的元素。

测试用例

要验证我们的 slice 方法实现是否正确,我们可以编写单元测试用例。这里我们使用了ArkTS和Jest测试框架,来确保我们的实现与ECMA规范一致。

const success = 0;
const fail = 1;
function testSliceWithOutParam(): int {let source: number[] = [10, 20, 30, 40, 50, 60];let ss = new ArrayBuffer(source.length as int * 1);let origin: Uint8Array;try {origin = new Uint8Array(ss);origin.set(source);} catch(e) {console.log(e);return fail;}let target: Uint8Array;try {target = origin.slice();} catch(e) {console.log(e);return fail;}if(target.length as int != origin.length as int) {console.log("Array length mismatch on slice");return fail;}//Check all the data copied;for(let i:int = 0; i< origin.length as int; i++) {let tv = target[i] as number;let ov = origin[i] as number;console.log(source[i] + "->" + tv + "->" + ov);if(tv != ov) {console.log("Array data mismatch");return fail;}}origin= new Uint8Array(0);if(origin.length as int != 0){return fail;}try {target = origin.slice();} catch(e) {console.log(e);return fail;}if(target.length as int != 0){return fail;}return success;
}function testSliceOneParam(): int {let source: number[] = [10, 20, 30, 40, 50, 60];let ss = new ArrayBuffer(source.length as int * 1);let origin: Uint8Array;try {origin = new Uint8Array(ss);origin.set(source);} catch(e) {console.log(e);return fail;}let sliceStart: int = 1;let sliceEnd: int = origin.length as int;let target: Uint8Array;try {target = origin.slice(sliceStart);} catch(e) {console.log(e);return fail;}if(target.length as int != origin.length as int - sliceStart) {console.log("Array length mismatch on slice One Params" + target.length);return fail;}//Check all the data copied;for(let i:int = sliceStart; i< sliceEnd; i++) {let tv = target[i - sliceStart] as number;let ov = origin[i] as number;console.log(source[i] + "->" + tv + "->" + ov);if(tv != ov) {console.log("Array data mismatch");return fail;}}sliceStart = 0;try {target = origin.slice(undefined);} catch(e) {console.log(e);return fail;}if(target.length as int != origin.length as int) {console.log("Array length mismatch on slice One Params" + target.length);return fail;}//Check all the data copied;for(let i:int = sliceStart; i< sliceEnd; i++) {let tv = target[i - sliceStart] as number;let ov = origin[i] as number;console.log(source[i] + "->" + tv + "->" + ov);if(tv != ov) {console.log("Array data mismatch");return fail;}}return success;
}function testSliceTwoParams(): int {let source: number[] = [10, 20, 30, 40, 50, 60, 70, 80];let ss = new ArrayBuffer(source.length as int * 1);let origin: Uint8Array;try {origin = new Uint8Array(ss);origin.set(source);} catch(e) {console.log(e);return fail;}let sliceStart: int = 2;let sliceEnd: int = 4;let target: Uint8Array;try {target = origin.slice(sliceStart, sliceEnd);} catch(e) {console.log(e);return fail;}if(target.length as int != sliceEnd - sliceStart) {console.log("Array length mismatch on slice2");return fail;}//Check all the data copied;for(let i:int = sliceStart; i< sliceEnd; i++) {let tv = target[i - sliceStart] as number;let ov = origin[i] as number;console.log(source[i] + "->" + tv + "->" + ov);if(tv != ov) {console.log("Array data mismatch");return fail;}}sliceStart = 0;sliceEnd = origin.length as int;try {target = origin.slice(sliceStart, sliceEnd);} catch(e) {console.log(e);return fail;}if(target.length as int != sliceEnd - sliceStart) {console.log("Array length mismatch on slice2");return fail;}//Check all the data copied;for(let i:int = sliceStart; i< sliceEnd; i++) {let tv = target[i - sliceStart] as number;let ov = origin[i] as number;console.log(source[i] + "->" + tv + "->" + ov);if(tv != ov) {console.log("Array data mismatch");return fail;}}try {target = origin.slice(new Number(sliceStart), undefined);} catch(e) {console.log(e);return fail;}if(target.length as int != sliceEnd - sliceStart) {console.log("Array length mismatch on slice2");return fail;}//Check all the data copied;for(let i:int = sliceStart; i< sliceEnd; i++) {let tv = target[i - sliceStart] as number;let ov = origin[i] as number;console.log(source[i] + "->" + tv + "->" + ov);if(tv != ov) {console.log("Array data mismatch");return fail;}}try {target = origin.slice(undefined, undefined);} catch(e) {console.log(e);return fail;}if(target.length as int != sliceEnd - sliceStart) {console.log("Array length mismatch on slice2");return fail;}//Check all the data copied;for(let i:int = sliceStart; i< sliceEnd; i++) {let tv = target[i - sliceStart] as number;let ov = origin[i] as number;console.log(source[i] + "->" + tv + "->" + ov);if(tv != ov) {console.log("Array data mismatch");return fail;}}try {target = origin.slice(undefined, new Number(sliceEnd));} catch(e) {console.log(e);return fail;}if(target.length as int != sliceEnd - sliceStart) {console.log("Array length mismatch on slice2");return fail;}//Check all the data copied;for(let i:int = sliceStart; i< sliceEnd; i++) {let tv = target[i - sliceStart] as number;let ov = origin[i] as number;console.log(source[i] + "->" + tv + "->" + ov);if(tv != ov) {console.log("Array data mismatch");return fail;}}try {target = origin.slice(0, 0);} catch(e) {console.log(e);return fail;}if(target.length as int != 0) {console.log("Array length mismatch on slice2");return fail;}return success;
}function testSliceTwoParamsWithOtherNumber(): int {let source: number[] = [10, 20, 30, 40, 50, 60, 70, 80];let ss = new ArrayBuffer(source.length as int * 1);let origin: Uint8Array;try {origin = new Uint8Array(ss);origin.set(source);} catch(e) {console.log(e);return fail;}let sliceStart: int = 4;let sliceEnd: int = 2;let target: Uint8Array;try {target = origin.slice(sliceStart, sliceEnd);} catch(e) {return fail;}if(target.length as int != 0) {console.log("Array length mismatch on slice2");return fail;}sliceStart = -1;sliceEnd = origin.length as int;try {target = origin.slice(sliceStart, sliceEnd);} catch(e) {return fail;}if(target.length as int != sliceEnd - (origin.length + sliceStart)) {console.log("Array length mismatch on slice2");return fail;}//Check all the data copied;for(let i:int = (origin.length + sliceStart) as int; i< sliceEnd; i++) {let tv = target[i - (origin.length + sliceStart)] as number;let ov = origin[i] as number;console.log(source[i] + "->" + tv + "->" + ov);if(tv != ov) {console.log("Array data mismatch");return fail;}}sliceStart = 0;sliceEnd = -origin.length as int;try {target = origin.slice(sliceStart, sliceEnd);} catch(e) {console.log(e);return fail;}if(target.length as int != (origin.length + sliceEnd) - sliceStart) {console.log("Array length mismatch on slice2");return fail;}return success;
}function testSliceOneLengthTwoParams(): int {let source: number[] = [10];let ss = new ArrayBuffer(source.length as int * 1);let origin: Uint8Array;try {origin = new Uint8Array(ss);origin.set(source);} catch(e) {console.log(e);return fail;}let sliceStart: int = 4;let sliceEnd: int = 2;let target: Uint8Array;try {target = origin.slice(sliceStart, sliceEnd);} catch(e) {return fail;}if(target.length as int != 0) {console.log("Array length mismatch on slice2");return fail;}sliceStart = 2;sliceEnd = 4;try {target = origin.slice(sliceStart, sliceEnd);} catch(e) {return fail;}if(target.length as int != 0) {console.log("Array length mismatch on slice2");return fail;}return success;
}

这些测试用例检查了 slice 方法在正常条件下和非正常条件下的行为。通过运行这些测试,我们可以确认我们的实现是否符合接口定义预期和ECMA规范。

总结来说,理解ECMA规范中的接口是任何ArkTS开发者的基本功,而且通过单元测试可以保证实现的准确性和可靠性。通过逐步实现这些接口并验证它们的行为,我们可以确保我们的ArkTS代码既强大又稳健。


最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?但是又不知道从哪里下手,而且学习时频繁踩坑,最终浪费大量时间。所以本人整理了一些比较合适的鸿蒙(HarmonyOS NEXT)学习路径和一些资料的整理供小伙伴学习

点击领取→纯血鸿蒙Next全套最新学习资料(安全链接,放心点击

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

一、鸿蒙(HarmonyOS NEXT)最新学习路线

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)…等技术知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

二、HarmonyOS Next 最新全套视频教程

三、《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

四、大厂面试必问面试题

五、鸿蒙南向开发技术

六、鸿蒙APP开发必备

七、鸿蒙生态应用开发白皮书V2.0PDF


完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

                        

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

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

相关文章

学期结束如何发布期末成绩?

当期末的试卷最后一张被收起&#xff0c;当教室里的喧嚣逐渐沉寂&#xff0c;学生们的心中充满了对成绩的期待与忐忑。期末成绩&#xff0c;关乎着学生的心情&#xff0c;更关系到他们的未来学习动力。那么&#xff0c;如何在保护学生隐私的同时&#xff0c;高效地公布成绩呢&a…

文件怎么加密?电脑文件加密,分享5个实用方法

通常情况下&#xff0c;人们对手机数据的保护比对电脑数据更为重视。许多人使用指纹和密码来防止他人窥视聊天记录和照片。然而&#xff0c;电脑上的数据却常常被忽视。大多数用户仅设置了电脑登录密码&#xff0c;认为这样就足以保护电脑和其中的文件。然而如果你也是这样认为…

chatglm系列知识

一、目录 chatglm 是什么语言模型与transformer decoder 的区别解释prefix LM与Cause LMchatglm&#xff08;prefix LM&#xff09;与decoder-only LM 核心区别glm 架构chatglm 预训练方式chatglm 微调chatglm与chatglm2、chatglm3的区别chatglm 激活函数采用gelu, 为什么chat…

办理北京公司注册地址异常变更要求和流程

在北京注册公司时选择注册地址是非常重要的一环&#xff0c;注册地址不仅体现在营业执照上&#xff0c;在网上也有公示信息&#xff0c;一般选用的是商用地址和商住两用地址&#xff0c;在公司经营过程中&#xff0c;因为经营需要变更注册地址&#xff0c;也要依法变更&#xf…

详解Spring AOP(一)

目录 1. AOP概述 2.Spring AOP快速入门 2.1引入AOP依赖 2.2编写AOP程序 3.Spring AOP核心概念 3.1切点&#xff08;PointCut&#xff09; 3.2连接点&#xff08;Join Point&#xff09; 3.3通知&#xff08;Advice&#xff09; 3.4切面&#xff08;Aspect&#xff09; …

时间?空间?复杂度??

1.什么是时间复杂度和空间复杂度&#xff1f; 1.1算法效率 算法效率分析分为两种&#xff1a;第一种是时间效率&#xff0c;第二种是空间效率。时间效率被称为时间复杂度&#xff0c;而空间效率被称为空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度&#xff0c;而空…

CentOS 8.5 - 配置ssh的免密登录

文章目录 生成ssh密钥公钥内容放入服务器 生成ssh密钥 在本地主机安装 ssh工具&#xff0c;并生成公钥、私钥。 # 命令行输入 ssh-keygen -r rsa# 会在当前用户的家目录下生成一个.ssh目录公钥内容放入服务器 将上一步生成的id_rsa.pub公钥的内容复制到远程服务器 # 编辑文…

Day17--654.最大二叉树+617.合并二叉树+700.二叉搜索树中的搜索+ 98.验证二叉搜索树

一、654.最大二叉树 题目链接&#xff1a;https://leetcode.cn/problems/maximum-binary-tree/ 文章讲解&#xff1a;https://programmercarl.com/0654.%E6%9C%80%E5%A4%A7%E4%BA%8C%E5%8F%89%E6%A0%91.html 视频讲解&#xff1a;https://www.bilibili.com/video/BV1MG411G7ox…

SpringMVC系列四: Rest-优雅的url请求风格

Rest请求 &#x1f49e;Rest基本介绍&#x1f49e;Rest风格的url-完成增删改查需求说明代码实现HiddenHttpMethodFilter机制注意事项和细节 &#x1f49e;课后作业 上一讲, 我们学习的是SpringMVC系列三: Postman(接口测试工具) 现在打开springmvc项目 &#x1f49e;Rest基本介…

Part 5.2 KMP

KMP 算法可以用来解决模式串匹配问题。 【模板】KMP 题目描述 给出两个字符串 s 1 s_1 s1​ 和 s 2 s_2 s2​&#xff0c;若 s 1 s_1 s1​ 的区间 [ l , r ] [l, r] [l,r] 子串与 s 2 s_2 s2​ 完全相同&#xff0c;则称 s 2 s_2 s2​ 在 s 1 s_1 s1​ 中出现了&…

「动态规划」如何求最长递增子序列的长度?

300. 最长递增子序列https://leetcode.cn/problems/longest-increasing-subsequence/description/ 给你一个整数数组nums&#xff0c;找到其中最长严格递增子序列的长度。子序列是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其…

使用Apache Flink实现实时数据同步与清洗:MySQL和Oracle到目标MySQL的ETL流程

使用Apache Flink实现实时数据同步与清洗&#xff1a;MySQL和Oracle到目标MySQL的ETL流程 实现数据同步的ETL&#xff08;抽取、转换、加载&#xff09;过程通常涉及从源系统&#xff08;如数据库、消息队列或文件&#xff09;中抽取数据&#xff0c;进行必要的转换&#xff0…

2024最新版Node.js下载安装及环境配置教程(非常详细)

一、进入官网地址下载安装包 官网&#xff1a;Node.js — Run JavaScript Everywhere 其他版本下载&#xff1a;Node.js — Download Node.js (nodejs.org) 选择对应你系统的Node.js版本 二、安装程序 &#xff08;1&#xff09;下载完成后&#xff0c;双击安装包&#xf…

Go的GUI Fyne开发环境搭建—Windows 11

安装go 到官网下载安装go安装包 https://go.dev/learn/ 通过如下命令检验安装是否成功&#xff0c;出现版本号则安装成功 go version安装国内go依赖包代理 go env -w GOPROXYhttps://goproxy.cn安装gcc编译器 直接用官网提供的安装建议第二条&#xff0c;到这个地址进行下载…

二刷算法训练营Day41 (Day40休息) | 动态规划(3/17)

目录 详细布置&#xff1a; 1. 背包问题理论基础 1.1 01背包 2. 46. 携带研究材料&#xff08;第六期模拟笔试&#xff09; 一维dp数组&#xff08;滚动数组&#xff09; 3. 416. 分割等和子集 详细布置&#xff1a; 1. 背包问题理论基础 但说实话&#xff0c;背包九讲…

C#开发-集合使用和技巧(六)特殊转换方法SelectMany的介绍和用法

C#开发-集合使用和技巧&#xff08;六&#xff09; 特殊转换方法SelectMany的介绍和用法 介绍使用示例Select与SelectMany对比特殊情况 介绍 SelectMany 方法在C#中用于将集合中的元素转换为其他类型的集合&#xff0c;并将这些集合扁平化为一个单一的序列。它是LINQ的一部分…

Unity URP下通过相机让部分Render不受后处理渲染

我们有时候不想某些对象受到后处理影响&#xff0c;找到了这样一个决绝办法&#xff0c;通过增加一个Overlay相机只照射这个模型来实现&#xff0c;下面看看如何实现。 第一步 首先我们拖一个测试场景&#xff0c;有如下一些元素 一个盒子&#xff0c;以后后处理&#xff0c…

Python武器库开发-武器库篇之ThinkPHP6 多语言本地文件包含漏洞(六十七)

Python武器库开发-武器库篇之ThinkPHP6 多语言本地文件包含漏洞&#xff08;六十七&#xff09; 漏洞环境搭建 这里我们使用Kali虚拟机安装docker并搭建vulhub靶场来进行ThinkPHP漏洞环境的安装&#xff0c;我们进入 ThinkPHP漏洞环境&#xff0c;可以 cd ThinkPHP&#xff0…

【Solr 学习笔记】Solr 源码启动教程

Solr 源码启动教程 本教程记录了如何通过 IDEA 启动并调试 Solr 源码&#xff0c;从 Solr9 开始 Solr 项目已由 ant 方式改成了 gradle 构建方式&#xff0c;本教程将以 Solr 9 为例进行演示&#xff0c;IDE 选择使用 IntelliJ IDEA。 Solr github 地址&#xff1a;https://gi…

【机器学习】机器学习重要方法——深度学习:理论、算法与实践

文章目录 引言第一章 深度学习的基本概念1.1 什么是深度学习1.2 深度学习的历史发展1.3 深度学习的关键组成部分 第二章 深度学习的核心算法2.1 反向传播算法2.2 卷积神经网络&#xff08;CNN&#xff09;2.3 循环神经网络&#xff08;RNN&#xff09; 第三章 深度学习的应用实…