Ada 语言学习(3)复合类型数据——Array

news2024/11/18 19:37:19

文章目录

  • Array
    • 数据类型声明
    • 数组索引
    • 数组范围
    • 数组复制
    • 数组初始化
      • 直接赋值
      • 通过拷贝赋值
        • 不同索引范围但长度相等
        • 非指定类型边界收缩
    • 多维数组
    • 数组遍历
    • 数组切片
    • 访问和动态检查
      • 直接访问
      • 动态检查
    • 数组字面量 Array literal
    • 数组拼接
      • 两个数组拼接
      • 数组和单个值拼接
    • Array Equality(数组相等判定)
    • 数组遍历
      • 通过索引遍历(循环变量I不可更改)
      • 直接遍历所有的对象 object(对象可以被更改)
    • 二维数组
    • 高维数组
  • Definite / indefinite types (定义类型和非定义类型)
    • String 字符串
    • 数组的默认值
    • Definite type (定义类型)
    • Indefinite type(非定义类型)
      • unconstrained type(未指定类型)
      • Generic type(泛型类型)
  • 练习

Array

数据类型声明

  • 在 Ada 中,可以使用 type 关键字声明数组类型,指定元素类型和维度 。例如:
    在这里插入图片描述
type IntArray is array(1 .. 10) of Integer;

数组索引

  • 数组中的索引是从 1 开始,默认情况下不支持从 0 开始,可以使用索引来访问数组的特定元素:IntArray(3) 表示 IntArray 数组的第 3 个元素。

数组范围

  • 数组的范围由其类型的索引范围定义。例如,IntArray 的索引范围是从 110

数组复制

在这里插入图片描述

  • 这里将 A2 的值复制给了 A1 但是, A1, A2 仍然是独立的两个数组, 在其他的编程语言中(有的是指向引用,但是 ada 不会这样,所有的 ada 复制都是 deep copy 操作)
  • 但是要求这两个数组的类型长度 必须是一致的。
    在这里插入图片描述
  • 在上面的复制中, A2 的内容复制给了 A1 ,因为虽然他们的索引范围不同,但是会对应复制,例如 A2(11) = A1(1) 以此类推
  • 但是 A3 的长度和 A1 不同,因此无法复制

数组初始化

  • 可以使用 := 运算符在声明数组时对其进行初始化,或者可以使用赋值语句逐个赋值。例如:

直接赋值

```ada
IntArray: IntArray := (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
```

通过拷贝赋值

不同索引范围但长度相等

在这里插入图片描述

  • 在上面的例子中,我们使用 非定义类型 的方式声明了一个类型 T,这是一个数组类型,但是 T 的范围我们并不知道,只知道 T 中的元素都是整数而已。
  • 同时 A1 数组是 T 类型,并且包含了 10 个元素,索引范围是 1-10
  • A2 数组也是 T 类型,并且包含了 10 个元素,索引范围是 11-20, 但是她复制了 A1 的值,虽然现在我们并不知道 A1 的值是什么。
  • 如果后面我们对 A1 的值进行修改,那么 A2 的值实际上并不会改变,因为 ada 的赋值是深拷贝
type T is array (Integer range <>) of Integer;
A1: T (1 .. 10);
A2: T (1 .. 10);

-- Fill A1 with some data.
for I in A1'Range loop
   A1(I) := I;
end loop;

-- Copy A1 to A2.
A2 := A1;

-- Change the value of A1(1)
A1(1) := 99;

-- Now, A1(1) is 99, but A2(1) is still 1.

非指定类型边界收缩

在这里插入图片描述

  • 如上图,如果 A1 是一个 T,并且 A1 数组的元素索引就是从 1-10,而这时,A2 复制了 A1 的值,虽然 A2 仍然是 T 类型(非定义类型),但是她也会复制 A1 的索引范围。

多维数组

  • Ada 支持多维数组的声明和操作。可以通过指定多个维度来声明多维数组,例如:
type Matrix is array(1 .. 3, 1 .. 3) of Integer;

数组遍历

可以使用 for 循环结构遍历数组中的元素。例如:

for i in IntArray'Range loop
   Put_Line(Integer'Image(IntArray(i)));
end loop;

数组切片

  • 可以使用数组切片(array slice)来访问数组的子集。切片允许通过指定范围来提取数组的一部分。例如:

    SubArray: IntArray := IntArray(3 .. 6);
    
    • SubArray 将包含 IntArray 数组索引为 3 到 6 的元素。
      在这里插入图片描述
  • 虽然在 copy 的时候,不同长度的 array 不能进行 copy 行为,但是我们可以 copy 其中的一部分。

  • 上图中 A2 的前 10 个元素复制给了 A1,然后 A12-4 索引的元素又获得了 A25-7 索引元素的值。

访问和动态检查

直接访问

  • ada 中的数组中的元素可以被直接访问:
    在这里插入图片描述
    • 这里定义了一个数组 V,他的索引范围是 1..10, 因此可以直接取 V(1)

动态检查

  • 数组会被进行动态检查:
    在这里插入图片描述
    • 因为这里的 V(0) 中的 0 并没有被覆盖在定义的索引范围中,因此这样是一种越界行为

数组字面量 Array literal

  • 可以使用 array literals(数组字面量) 来初始化数组或者赋值给数组。数组字面量是由一系列逗号分隔的值,这些值被括在括号内。

  • 例如,可以使用数组字面量来初始化一个数组:

    type T is array (1 .. 5) of Integer;
    A : T := (1, 2, 3, 4, 5); -- array literal
    
  • 在这个例子中,(1, 2, 3, 4, 5) 是一个数组字面量,用来初始化数组 A。

  • 也可以使用数组字面量来给数组赋值:

    A := (6, 7, 8, 9, 10); -- array literal
    
  • 此外,Ada 语言还提供了 others 关键字来初始化或赋值数组中剩余的所有元素:

    A := (1, 2, others => 3); -- array literal with 'others'
    

在这里插入图片描述

  • 需要特别注意的是:在使用数组字面量进行初始化的时候,要注意分清楚下面的情况:
    在这里插入图片描述
    • V1 虽然是一个 非指定类型 的数组,但是由于其索引就只有 3 个,因此我们可以使用 others 来为 V1 中的所有的元素赋值
    • 但是 V2 没有指定元素的个数,而直接使用 others 这种情况在 ada 中是不被允许的

数组拼接

两个数组拼接

在这里插入图片描述

  • 通过 & 符号,可以直接拼接两个一维的数组

那现在就有疑问了,假设 A1 的索引范围是 (1..10)A2
的索引范围是 (8..12),那么 A3 作为 A1 & A2 的结果,索引范围应该会是什么样子?

  • 其实是这个完全不需要担心,因为再给 A3 赋值之前,我们需要先定义 A3 的索引,例如下面的代码:
type T is array (Integer range <>) of Integer;
A1: T (1 .. 10);
A2: T (8 .. 12);
A3: T (1 .. 15);  -- The range of A3 should be the total length of A1 and A2.

-- Fill A1 and A2 with some data.
for I in A1'Range loop
   A1(I) := I;
end loop;

for I in A2'Range loop
   A2(I) := I;
end loop;

-- Concatenate A1 and A2.
A3 := A1 & A2;
  • 可以看到,其实我们只需要关注 A3 的元素个数即可,而不用担心元素的索引。

数组和单个值拼接

在这里插入图片描述

Array Equality(数组相等判定)

在这里插入图片描述

  • 数组的 size 需要相等
  • 数组中的每个元素都必须相等
  • 数组的类型必须相等
  • 数组的索引范围不影响数组的相等判定
    type T is array (Integer range <>) of Integer;
    
    A1 : T (1 .. 3) := (1, 2, 3);
    A2 : T (2 .. 4) := (1, 2, 3);
    
    -- This will print "Equal"
    if A1 = A2 then
       Put_Line("Equal");
    else
       Put_Line("Not Equal");
    end if;
    

数组遍历

通过索引遍历(循环变量I不可更改)

在这里插入图片描述

  • 使用 A 数组的 Range 属性来得到所有的索引,并进行遍历
  • 但是使用的循环变量 I 是不可以被修改的

直接遍历所有的对象 object(对象可以被更改)

在这里插入图片描述

  • 使用 of 关键字
  • 如果我在循环中更改了 V (如上图)那么这个 V 就会切实地被更改成 0

二维数组

在这里插入图片描述

高维数组

type T1 is array (Integer range <>) of Integer;
type T2 is array (Integer range <>) of T1 (0 .. 2); -- specify the range of T1 here

V: T2 (1 .. 10);
begin
    V (1)(0) := 0; -- Now this is OK.
end;
  • 在这段代码中,V 是一个 T2 类型的数组,其中每个元素都是一个 T1 类型的数组。T1 类型的数组的范围是 0 .. 2,因此 V (1)(0) := 0; 这行代码现在是正确的,它将 V 的第1个元素(一个 T1 类型的数组)的第0个元素设置为 0
  • 在定义一个多维数组的后面的维度的时候,需要将前面的维度都定义好

所以这是一个几行几列的数组?

  • 类型 T2 定义为 type T2 is array (Integer range <>) of T1 (0 .. 2);,其中每个元素都是一个 T1 类型的数组(这里,T1 的范围是 0 .. 2,因此 T1 类型的数组有3个元素)。

因此,当你声明 V: T2 (1 .. 10); 时,你正在创建一个有10行、每行3列的二维数组。具体来说,这是一个10行3列的数组。

对于一个 ada 中的 2维数组 V, 那么 V(0)(1) 和 V(0,1) 是相等的么

  • 是的,V(0)(1)V(0,1) 在 Ada 中是等价的。它们都是用来访问二维数组 V 中的特定元素。具体来说,它们都访问的是 V 的第 0 行第 1 列的元素。V(0,1) 的写法可能在阅读和理解代码时更清晰,因为它明确表示了这是一个二维索引,而 V(0)(1) 则可能需要更多的解析才能理解。

Definite / indefinite types (定义类型和非定义类型)

在这里插入图片描述

String 字符串

  • 在 Ada 语言中,字符串被视为一种特殊类型的数组,其索引是 Positive 范围的整数(也就是从 1 开始的整数),而元素类型是 Character。这意味着可以像处理其他数组一样来处理字符串,比如用下标来访问特定字符,或者用 'Length 属性来获取字符串的长度。
S : String := "Hello, world!";
Put_Line("The first character is: " & S(1));
Put_Line("The length of the string is: " & Integer'Image(S'Length));
  • 此外,还要注意的是 Ada 中的字符串是不可变的。也就是说,一旦一个字符串被创建,就不能修改它的内容。不过,可以通过字符串拼接操作(用 & 运算符)来创建新的字符串。比如:
S1 : String := "Hello";
S2 : String := ", world!";
S3 : String := S1 & S2;  -- S3 is now "Hello, world!"
  • 但如果你需要一个可变的字符串,你可以使用 Unbounded_String 类型,这是 Ada 的标准库 Ada.Strings.Unbounded 中提供的一种类型。Unbounded_String 类型的对象可以通过 To_Unbounded_String 函数从普通字符串创建,可以用 To_String 函数转回普通字符串,也可以用 &= 运算符来修改内容。
    在这里插入图片描述

数组的默认值

  • 在 Ada 语言中,当你声明一个数组但不给它赋初始值时,数组的元素将不会被自动初始化为默认值。相反,数组元素的初始值是不确定的。这与许多其他编程语言有所不同,这些语言可能会给新的数组元素自动赋予默认值。

  • 如果你想给数组的所有元素赋予相同的初始值,你可以使用 (others => value) 语法,其中 value 是你想要赋予的初始值。例如,以下代码将创建一个浮点数数组 A,并将其所有元素初始化为 0.0

    type T is array (Integer range <>) of Float;
    A : T (1 .. 10) := (others => 0.0);
    
  • 请注意,(others => value) 只能用于初始化数组。如果你在后续的代码中想要修改数组的所有元素,你需要使用一个循环来遍历数组并为每个元素赋值。

  • 当然也可以强迫数组拥有默认值:
    在这里插入图片描述

  • 为了性能考虑,上述代码一般不会使用

Definite type (定义类型)

  • 定义类型是通过使用 type 关键字显式定义的类型。它们是具体的类型,具有明确定义的结构和语义。定义类型可以是基本类型(如 Integer、Float、Boolean)或派生类型(通过限定范围、枚举、数组等方式创建的类型)。例如:

    type MyInteger is range 1 .. 10;
    

Indefinite type(非定义类型)

  • 非定义类型是一种未具体定义的类型,它们是一种抽象概念,没有具体的结构和语义。它们通常用作模板或占位符,在需要时可以被实例化为具体的类型

  • Ada 中的非定义类型包括未指定类型(unconstrained type)和泛型类型(generic type)。

unconstrained type(未指定类型)

  • 未指定类型:未指定类型是一种可以通过参数传递进行实例化的占位符类型。它们在声明时不指定范围或大小,需要在使用时提供具体的值或范围。

      ```ada
      type MyUnconstrainedArray is array (Positive range <>) of Integer;
      ```
    
    • 在上述示例中,MyUnconstrainedArray 是一个未指定类型的数组类型,可以根据实际需要传递不同的范围进行实例化。
    • Positive 被用作 array 的索引范围。通过使用 Positive range <>,表示数组的索引可以是任意的正整数范围。
    • 例如,可以将 MyUnconstrainedArray 实例化为索引范围为 1 到 100 的数组:
      MyArray : MyUnconstrainedArray(1 .. 100);
      
    • 使用 Positive 子类型作为数组索引范围的好处是,它可以确保索引始终是正整数,符合实际需求,并提供了类型安全性。

Generic type(泛型类型)

  • 泛型类型是一种可以根据参数化的类型或值来创建通用代码模板的类型。它们在定义时可以指定一个或多个参数,然后在使用时提供具体的参数值来实例化
    例如:

    generic
       type ElementType is private;
    package Stack is
       type Stack_Type is private;
       procedure Push(Item : in ElementType);
       function Pop return ElementType;
       ...
    end Stack;
    
  • 在上述示例中,Stack 是一个泛型包(generic package),使用了一个参数 ElementType。这个参数 ElementType 可以是任意类型,它在使用时可以通过传递具体的类型来实例化。也就是说,可以使用不同的类型来创建不同类型的堆栈。

  • 例如,可以使用 Stack 泛型包创建一个整数类型的堆栈:

    package Integer_Stack is new Stack(ElementType => Integer);
    

非定义类型 (indefinite types) 的灵活性和可扩展性使得它们在处理通用数据结构和算法时非常有用。通过使用非定义类型,可以编写更通用和可复用的代码,适应不同的数据类型和需求。

练习

在这里插入图片描述
在这里插入图片描述

  • 这种情况的类型定义没问题,但是没有限定数组的大小,因此会报错

在这里插入图片描述

  • 从结构上来说,他们都是长度为 3 的数组,
  • 但是他们不是同一个 type,虽然他们的 type 定义看起来完全一样的,但是却并不符合数组复制的要求

在这里插入图片描述

  • 在 Ada 中,数组的默认索引起始值是 1,而不是像一些其他语言(如 C 或 Python)那样是 0。因此,V (0) 是无效的,会导致范围错误。

  • 在代码中创建了一个名为 V 的数组,类型为 T,并将其初始化为 (1, 2, 3)。这将创建一个包含三个元素的数组,这些元素的索引是 1、23

在这里插入图片描述
在这里插入图片描述

  • 开始 X=10 ,即,V1 创建出来的时候具备 10 个元素
  • 虽然后来 X 的值修改为 100,但是 V1 已经固定了,
  • 因此可以直接将 V2 复制给 V1

在这里插入图片描述

  • 从定义中我们只知道 V1 的索引范围是 1-3 并且给定了 3 个值
  • 同时我们知道 V2 的值也是 (10, 20, 30)
  • 但是定义中并没有明确指定 V2 的 boundary,也就是索引范围,因此我们并不能够盲目推测
  • 也就是当 I=1 时,我们无法确定 V2 的值,对 V2来说,因为没有给定 boundary,所以 V2 的第一个索引其实是 -2^16(也就是 integer 类型中最小的数)

在这里插入图片描述

  • 这里是通过 definite 的方式来定义数组, Tboundary 固定为 1-10,因此不能被随意改变,如果这里使用的是 indefinite 的形式,例如 type T is array(Integer range<>) of Integer 那么在定义 V 的时候是可以更改 boundary

在这里插入图片描述

  • 在 Ada 中,String 是一种预定义的数组类型,其元素类型为 Character。在 Ada 中,没有直接创建字符串数组的方式。通常,你会创建一个数组,它的元素类型是固定长度的字符串,或者是 Unbounded_String
  • 同时,如果创建一个字符串,那么对于索引类型 Integer range <> 也要更改为 Positive range <> 因为在 Ada 中,String 是一种特定类型的数组,其索引类型是 Positive

如果你想创建一个可以存储任意长度字符串的数组,你可以使用 Ada.Strings.Unbounded.Unbounded_String 类型。这个类型可以存储任意长度的字符串,并提供了一些实用的操作。以下是一个示例:

	with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
	type String_Array is array (Integer range <>) of Unbounded_String;
  • 如果你只需要处理固定长度的字符串,你可以这样定义:
	type String_Array is array (Integer range <>) of String (1 .. Max_Length);
  • 在这个例子中,Max_Length 是一个你预先定义的常量,表示字符串的最大长度。这种方式的限制是所有的字符串都必须有相同的长度,而且这个长度是在编译时决定的。

在这里插入图片描述

  • 在 Ada 中,Default_Component_Value 属性应用于类型标签,并将默认值分配给类型的每个实例的组件。但是,此默认值必须是编译时可以确定的值,不能是变量。以上代码中,尝试将变量 X 作为默认组件值,这是不允许的。

  • 如果希望每个数组元素的默认值为 0,那么应该直接使用数值 0,而不是变量 X。下面是修改后的代码:

    type T is array (Integer range <>) of Integer with Default Component Value => 0;
    V: T(1 .. 10);
    
  • 如果 X 的值在编译时可以确定,那么也可以使用常量来替代变量,如下:

    X: constant Integer := 0;
    type T is array (Integer range <>) of Integer with Default Component Value => X;
    V: T(1 .. 10);
    

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

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

相关文章

机器学习平台 PAI 支持抢占型实例,模型服务最高降本 90%

助力模型推理服务降本增效&#xff0c;适用于推理成本敏感场景&#xff0c;如&#xff1a;AIGC 内容生成异步推理、批量图像处理、批量音视频处理等。 在 AI 开发及服务不断追求效率的背景下&#xff0c;阿里云机器学习平台 PAI 宣布支持抢占型实例&#xff08;Spot Instance&a…

2023逆向分析代码渗透测试flag0072解析(超详细)

一、竞赛时间 180分钟 共计3小时 1.从靶机服务器的FTP上下载flag0072,分析该文件,请提交代码保护技术的类型。提交格式:XXXX。 2.提交被保护的代码所在地址。提交格式: 0xXXXX。 3.提交代码解密的密钥。提交格式: 0xXX。 4.请提交输入正确flag时的输出。提交格式: XXXX。…

Python入门(十二)while循环(二)

while循环&#xff08;二&#xff09; 1.使用while循环处理列表和字典2.在列表之间移动元素3.删除为特定值的所有列表元素4.使用用户输入来填充字典 作者&#xff1a;xiou 1.使用while循环处理列表和字典 到目前为止&#xff0c;我们每次都只处理了一项用户信息&#xff1a;获…

建站教程:腾讯云轻量服务器安装宝塔面板搭建网站流程

腾讯云轻量应用服务器镜像选择宝塔Linux面板&#xff0c;然后在宝塔面板上安装LNMP网站所需的Web环境&#xff0c;在宝塔面板上新建站点&#xff0c;上床网站程序安装包到根目录&#xff0c;并安装网站全流程。腾讯云百科来详细说下腾讯云轻量应用服务器搭建网站全流程&#xf…

百果园ESG:围绕“好吃”二字,勾勒水果行业未来蓝图

当一场可持续绿色变革开始&#xff0c;ESG&#xff08;环境、社会与治理&#xff09;已经成为企业发展战略的重要组成部分。 然而&#xff0c;如何实现ESG和企业发展的协同却是一大问题。根据毕马威《2022年中国首席执行官展望》&#xff0c;一些企业家也表示ESG投资对提升财务…

SpringBoot配置文件3种格式、配置文件读取方式、多环境配置、配置文件优先级分类

文章目录 1 配置文件格式1.1 环境准备1.2 不同配置文件演示1.3 三种配合文件的优先级 2 yaml格式2.1 语法规则 3 yaml配置文件数据读取3.1 环境准备3.2 读取配置数据方式1 使用 Value注解方式2 Environment对象方式3 自定义对象 4 多环境配置4.1 yaml文件4.2 properties文件4.3…

H.265/HEVC编码原理及其处理流程的分析

H.265/HEVC编码原理及其处理流程的分析 H.265/HEVC编码的框架图&#xff0c;查了很多资料都没搞明白&#xff0c;各个模块的处理的分析网上有很多&#xff0c;很少有把这个流程串起来的。本文的主要目的是讲清楚H.265/HEVC视频编码的处理流程&#xff0c;不涉及复杂的计算过程。…

自定义线程池 ThreadPoolExecutor

ThreadPoolExecutor 自定义线程池 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultT…

Arduino ESP8266+RC522+阿里云 物联网入户控制RFID门禁系统

前言 根据项目结课报告改编而成&#xff0c;可能更适合作为一份文档而不是一篇记录类型的博客&#xff0c;没有留存接线图和运行图片&#xff0c;感到抱歉。 使用的板子是YwRobot的ESP8266板子&#xff0c;使用Arduino IDE开发&#xff0c;用到了舵机、按钮、人体感应传感器、…

Unity UI -- (4)用图像创建菜单背景

添加一个基础的设置菜单背景 设置菜单的元素会安放在一个简单的矩形区域上。我们用一个Image对象来创建这个矩形。 1. 首先&#xff0c;我们暂时停用Title Text和Settings Button游戏物体。这样会让我们的Canvas看起来更清爽。 2. 在Hierarchy中&#xff0c;点击右键&#xff0…

探索云原生世界:当前最受欢迎的技术和趋势

文章目录 探索云原生世界&#xff1a;当前最受欢迎的技术和趋势引言&#xff1a;一、云原生概述&#xff1a;1. 什么是云原生&#xff1f;2. 为什么云原生重要&#xff1f;3. 云原生的核心原则和特征。4. 云原生的优势和挑战。 二、核心技术与工具&#xff1a;1. Kubernetes&am…

C语言qsort函数、活字印刷、cmd窗口

一、qsort函数 qsort函数就是快排&#xff0c;可以不用写那么一长串的代码了qvq&#xff0c;要用到stdlib.h库文件 那么具体用法就是 oid qsort(void* base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*)); 当然我们还要用一个比较函数来确定快排…

手机APP性能测试工具PerfDog性能狗安装教程及简单使用

一、前言 PerfDog是一个由腾讯研发的主流性能测试软件。可以提高软件和游戏的运行效率&#xff0c;支持iOS/安卓在移动平台上的性能测试和分析&#xff0c;快速定位和分析性能问题等。无需安装&#xff0c;即插即用&#xff0c;减少繁琐的测试障碍&#xff0c;安卓设备不需要RO…

PCB基础~PCB介质,Vias

PCB介质 • 一般的介质材料 – FR-4&#xff08;玻璃纤维和环氧基树脂交织而成&#xff09; • 最常和最广泛使用&#xff0c;相对成本较低 • 介电常数&#xff1a;最大4.7&#xff0c; 4.35500Mhz,4.341Ghz • 可承受的最高信号频率是2Ghz(超过这个值&#xff0c;损耗和串扰…

IDEA中怎么把jar包导入项目中

大作业让生成一个pdf&#xff0c;查找资料发现可以通过pdfbo相关函数调用&#xff0c;但本地缺少这个文件&#xff0c;以这个文件为例子。 一、下载 下载去Apache上下载&#xff0c;Apache PDFBox | Download&#xff0c;&#xff0c;结合自己的java版本啥的下载就行。 我是…

java中使用java8的stream报错java.lang.IllegalStateException: Duplicate key

一、java.lang.IllegalStateException: Duplicate key报错的原因 map的key重复导致的报错Duplicate key 二、java.lang.IllegalStateException: Duplicate key报错的解决方式 list.stream().collect()就是把一个List的查询数据集合转为一个Map&#xff0c;java8的stream方式…

UE5 C++类如何打印日志?

UE5 插件开发指南 前言0. 什么是日志?1.在哪里可以查看日志呢?2. 日志有哪些等级?3. 如何打印到屏幕上?4. 如何更专业的记录日志?4.0 UE_LOG宏语法4.1 自定义日志类别4.2 插件中的日志类别定义前言 在回答这个问题之前,先要给萌新科普一下:什么是日志?以及,在哪里查看日…

自己动手写一个加载器

前言 当在 linux 命令行中 ./ 运行一个程序时&#xff0c;实际上操作系统会调用加载器将这个程序加载到内存中去执行。为了探究加载器的行为&#xff0c;今天我们就自己动手写一个简单的加载器。 工作原理 加载器的工作原理&#xff1a; 从磁盘读取 bin 文件到内存&#xf…

【Python html常用标签】零基础也能轻松掌握的学习路线与参考资料

学习路线 要深入了解Python html常用标签&#xff0c;需要遵循以下学习路线&#xff1a; 1.1 HTML基础知识&#xff1a;了解HTML语言的起源&#xff0c;HTML文档结构和基本标签。学习HTML标签包含但不限于文本标签&#xff0c;图像标签&#xff0c;链接标签&#xff0c;表格标…

canvas的HTML和JavaScript

文章目录 一、canvas元素二、前期准备1. 坐标系2. canvas属性① 获取canvas元素② 把canvas实例化为2D③ 设置路径颜色④ 设置路径宽度⑤ 设置路径末端形状⑥ 设置路径相连时的相连部分形状⑦ 透明度⑦ 虚线 三、绘制图行1. 绘制线段2. 绘制三角形① 空心三角形② 实心三角形 3…