Day 05 - 数组和元组深入
目标:掌握ArkTS数组的声明、操作、高级方法和元组类型
预计时间:2-3小时
第一部分:数组声明与基本操作
1.1 声明方式(类型[] 和 Array<类型>)
ArkTS提供两种等价的数组声明语法:
// 方式一:类型[](推荐,更简洁)
let deviceIds: number[] = [1001, 1002, 1003, 1004];
let deviceNames: string[] = ["温度传感器-01", "湿度传感器-02", "光照传感器-03"];
let deviceStatuses: boolean[] = [true, false, true];
// 方式二:Array<类型>(泛型写法)
let voltages: Array<number> = [220, 380, 110, 220];
let sensorTypes: Array<string> = ["TEMP", "HUMI", "LIGHT", "PRESS"];
⚠️ ArkTS 空数组必须显式声明类型:
// ⚠️ 推断为 never[],无法添加元素
// let emptyDevices = []; // 类型为 never[],后续无法 push
// ✅ 正确:显式声明类型
let emptyDevices: string[] = [];
let emptyValues: Array<number> = [];
let sensorReadings: number[] = []; // 准备存储传感器读数
1.2 多维数组
二维数组常用于存储矩阵型数据,如传感器网格读数:
// 二维数组:3x3传感器网格的温度读数
let temperatureGrid: number[][] = [
[25.5, 26.0, 24.8],
[26.2, 27.1, 25.9],
[24.5, 25.3, 26.7]
];
// 访问元素:第2行第3列(0-based索引)
let centerTemp: number = temperatureGrid[1][2]; // 25.9
console.log(`中心区域温度:${centerTemp}°C`);
// 修改元素
temperatureGrid[0][0] = 26.5;
// 三维数组:多层楼宇传感器数据
let buildingSensors: number[][][] = [
[ // 第1层
[22.5, 23.0], // 房间1的温度、湿度
[23.5, 45.0] // 房间2的温度、湿度
],
[ // 第2层
[24.0, 42.0],
[25.5, 48.0]
]
];
// 访问:第2层第1个房间的温度
let roomTemp: number = buildingSensors[1][0][0]; // 24.0
console.log(`2层1号房间温度:${roomTemp}°C`);
1.3 访问与修改(越界返回undefined,不崩溃)
let devices: string[] = ["DEV-001", "DEV-002", "DEV-003"];
// 访问元素(0-based索引)
let firstDevice: string = devices[0]; // "DEV-001"
let secondDevice: string = devices[1]; // "DEV-002"
// 修改元素
devices[1] = "DEV-002-UPDATED";
console.log(`更新后的设备列表:${devices.join(", ")}`);
// 越界访问(不会崩溃,返回undefined)
let outOfBound: string | undefined = devices[10];
console.log(`越界访问结果:${outOfBound}`); // "undefined"
// 安全访问模式
let index: number = 5;
if (index < devices.length) {
console.log(`设备:${devices[index]}`);
} else {
console.log(`索引${index}超出范围,数组长度为${devices.length}`);
}
⚠️ 与C++的重要区别:C++数组越界是未定义行为(可能崩溃),ArkTS数组越界安全地返回undefined。
1.4 获取长度(.length 是属性不是方法)
let sensorData: number[] = [23.5, 24.0, 22.8, 25.2];
// length是属性,不是方法,不需要括号
let count: number = sensorData.length; // 4
console.log(`传感器数据点数量:${count}`);
// 实际应用:计算平均值
let sum: number = 0;
for (let i: number = 0; i < sensorData.length; i++) {
sum += sensorData[i];
}
let average: number = sum / sensorData.length;
console.log(`平均温度:${average.toFixed(2)}°C`);
// 空数组检查
let pendingDevices: string[] = [];
if (pendingDevices.length === 0) {
console.log("没有待处理设备");
}
【小结表格】
| 操作 | 语法 | 示例 | 说明 |
|---|---|---|---|
| 声明数组(推荐) | 类型[] |
let arr: number[] = [1, 2, 3] |
- |
| 声明数组(泛型) | Array<类型> |
let arr: Array<number> = [1, 2, 3] |
- |
| 声明空数组 | 必须显式类型 | let arr: string[] = [] |
否则推断为never[] |
| 访问元素 | arr[index] |
let x: number = arr[0] |
- |
| 修改元素 | arr[index] = value |
arr[0] = 100 |
- |
| 获取长度 | arr.length |
let n: number = arr.length |
属性,不是方法 |
| 越界访问 | 返回undefined |
arr[100] → undefined |
安全,不崩溃 |
第二部分:数组增删操作
2.1 push/pop(末尾增删)
let deviceQueue: string[] = ["DEV-A", "DEV-B"];
// push:在末尾添加一个或多个元素
// ArkTS支持多参数push
deviceQueue.push("DEV-C"); // ["DEV-A", "DEV-B", "DEV-C"]
deviceQueue.push("DEV-D", "DEV-E"); // ["DEV-A", "DEV-B", "DEV-C", "DEV-D", "DEV-E"]
console.log(`添加后队列:${deviceQueue.join(", ")}`);
// pop:删除并返回末尾元素
let lastDevice: string | undefined = deviceQueue.pop(); // "DEV-E"
console.log(`移除的设备:${lastDevice}`);
console.log(`剩余队列:${deviceQueue.join(", ")}`);
// 空数组pop返回undefined
let emptyArr: string[] = [];
let result: string | undefined = emptyArr.pop(); // undefined
console.log(`空数组pop结果:${result}`);
2.2 unshift/shift(开头增删)
let taskQueue: string[] = ["任务2", "任务3"];
// unshift:在开头添加一个或多个元素
taskQueue.unshift("任务1"); // ["任务1", "任务2", "任务3"]
taskQueue.unshift("紧急任务", "优先任务"); // ["紧急任务", "优先任务", "任务1", "任务2", "任务3"]
console.log(`任务队列:${taskQueue.join(" → ")}`);
// shift:删除并返回开头元素(FIFO队列)
let currentTask: string | undefined = taskQueue.shift(); // "紧急任务"
console.log(`当前执行任务:${currentTask}`);
console.log(`剩余任务:${taskQueue.join(" → ")}`);
// IoT场景:处理传感器数据流
let sensorBuffer: number[] = [];
sensorBuffer.push(23.5); // 新数据入队
sensorBuffer.push(24.0);
sensorBuffer.push(22.8);
while (sensorBuffer.length > 0) {
let reading: number | undefined = sensorBuffer.shift();
if (reading !== undefined) {
console.log(`处理读数:${reading}°C`);
}
}
⚠️ 性能提示:unshift和shift需要移动所有现有元素,对于大数组效率较低。频繁在开头操作可考虑使用其他数据结构。
2.3 splice(删除/插入元素)
let deviceList: string[] = ["DEV-001", "DEV-002", "DEV-003", "DEV-004", "DEV-005"];
// splice(start, deleteCount, ...items):从start位置删除deleteCount个元素,并可插入新元素
// 返回被删除的元素数组
// 从索引2开始删除1个元素
let removed: string[] = deviceList.splice(2, 1);
console.log(`被删除:${removed.join(", ")}`); // "DEV-003"
console.log(`剩余:${deviceList.join(", ")}`); // ["DEV-001", "DEV-002", "DEV-004", "DEV-005"]
// 从索引1开始删除2个元素
let removed2: string[] = deviceList.splice(1, 2);
console.log(`被删除:${removed2.join(", ")}`); // "DEV-002, DEV-004"
console.log(`剩余:${deviceList.join(", ")}`); // ["DEV-001", "DEV-005"]
// 在索引1处插入元素(删除0个,插入新元素)
let arr: number[] = [10, 20, 30, 50];
arr.splice(2, 0, 25); // 在索引2处插入25
console.log(`插入后:${arr.join(", ")}`); // [10, 20, 25, 30, 50]
// 从末尾删除:使用负数索引
let arr2: number[] = [10, 20, 30, 40, 50];
arr2.splice(-2, 1); // 删除倒数第2个元素(40)
console.log(`结果:${arr2.join(", ")}`); // [10, 20, 30, 50]
2.4 concat(拼接数组)
let onlineDevices: string[] = ["DEV-A", "DEV-B"];
let offlineDevices: string[] = ["DEV-C", "DEV-D"];
let newDevices: string[] = ["DEV-E"];
// concat:合并多个数组,不修改原数组
let allDevices: string[] = onlineDevices.concat(offlineDevices);
console.log(`合并后:${allDevices.join(", ")}`);
// 可以链式拼接多个数组
let completeList: string[] = onlineDevices.concat(offlineDevices, newDevices);
console.log(`完整列表:${completeList.join(", ")}`);
// 原数组保持不变
console.log(`onlineDevices未改变:${onlineDevices.join(", ")}`);
// 添加单个元素
let withNew: string[] = onlineDevices.concat("DEV-F");
console.log(`添加单个:${withNew.join(", ")}`);
2.5 slice(提取子数组)
let sensorReadings: number[] = [22.5, 23.0, 24.5, 25.0, 26.5, 27.0];
// slice(start, end?):提取从start到end(不包含)的子数组
// 不修改原数组
// 提取索引1到3(不包含3)
let subset1: number[] = sensorReadings.slice(1, 4); // [23.0, 24.5, 25.0]
console.log(`子数组1:${subset1.join(", ")}`);
// 从索引2到末尾
let subset2: number[] = sensorReadings.slice(2); // [24.5, 25.0, 26.5, 27.0]
console.log(`子数组2:${subset2.join(", ")}`);
// 负数索引:从末尾计数
let lastTwo: number[] = sensorReadings.slice(-2); // [26.5, 27.0]
let middle: number[] = sensorReadings.slice(1, -1); // [23.0, 24.5, 25.0, 26.5]
console.log(`最后两个:${lastTwo.join(", ")}`);
console.log(`去掉首尾:${middle.join(", ")}`);
// 原数组保持不变
console.log(`原数组:${sensorReadings.join(", ")}`);
【小结表格】
| 方法 | 作用 | 修改原数组 | 返回值 |
|---|---|---|---|
push(...items) |
末尾添加 | ✅ 是 | 新长度 |
pop() |
删除末尾 | ✅ 是 | 被删元素/undefined |
unshift(...items) |
开头添加 | ✅ 是 | 新长度 |
shift() |
删除开头 | ✅ 是 | 被删元素/undefined |
splice(start, count, ...items) |
删除/插入 | ✅ 是 | 被删元素数组 |
concat(...arrays) |
拼接数组 | ❌ 否 | 新数组 |
slice(start?, end?) |
提取子数组 | ❌ 否 | 新数组 |
第三部分:数组查找与判断
3.1 indexOf / includes
let deviceIds: number[] = [1001, 1002, 1003, 1004, 1005];
// indexOf:查找元素索引,找不到返回-1
let idx1: number = deviceIds.indexOf(1003); // 2
let idx2: number = deviceIds.indexOf(9999); // -1(不存在)
console.log(`1003的索引:${idx1}`);
console.log(`9999的索引:${idx2}`);
// 指定起始搜索位置
let idx3: number = deviceIds.indexOf(1001, 1); // -1(从索引1开始找,找不到1001)
// includes:判断是否包含元素
let has1002: boolean = deviceIds.includes(1002); // true
let has9999: boolean = deviceIds.includes(9999); // false
// IoT场景:检查设备是否在白名单中
let whitelist: number[] = [1001, 1003, 1005];
let deviceId: number = 1003;
if (whitelist.includes(deviceId)) {
console.log(`设备${deviceId}在白名单中,允许连接`);
} else {
console.log(`设备${deviceId}未授权,拒绝连接`);
}
3.2 find / findIndex
interface Device {
id: number;
name: string;
online: boolean;
}
let devices: Device[] = [
{ id: 1001, name: "温度传感器A", online: true },
{ id: 1002, name: "湿度传感器B", online: false },
{ id: 1003, name: "光照传感器C", online: true }
];
// find:返回第一个满足条件的元素,找不到返回undefined
let onlineDevice: Device | undefined = devices.find((d: Device) => d.online === true);
if (onlineDevice !== undefined) {
console.log(`找到在线设备:${onlineDevice.name}`);
}
// findIndex:返回第一个满足条件的索引,找不到返回-1
let offlineIdx: number = devices.findIndex((d: Device) => d.online === false);
console.log(`第一个离线设备索引:${offlineIdx}`); // 1
// 复杂条件查找
let targetDevice: Device | undefined = devices.find((d: Device) => {
return d.id > 1001 && d.online === true;
});
console.log(`ID>1001的在线设备:${targetDevice?.name ?? "无"}`);
3.3 some / every
interface Sensor {
id: number;
type: string;
value: number;
normal: boolean;
}
let sensors: Sensor[] = [
{ id: 1, type: "TEMP", value: 25.5, normal: true },
{ id: 2, type: "HUMI", value: 60.0, normal: true },
{ id: 3, type: "TEMP", value: 85.0, normal: false }
];
// some:是否有至少一个元素满足条件
let hasAbnormal: boolean = sensors.some((s: Sensor) => s.normal === false);
console.log(`是否有异常传感器:${hasAbnormal}`); // true
let hasHighTemp: boolean = sensors.some((s: Sensor) => s.type === "TEMP" && s.value > 80);
console.log(`是否有高温警报:${hasHighTemp}`); // true
// every:是否所有元素都满足条件
let allNormal: boolean = sensors.every((s: Sensor) => s.normal === true);
console.log(`是否全部正常:${allNormal}`); // false
let allHaveId: boolean = sensors.every((s: Sensor) => s.id > 0);
console.log(`是否都有有效ID:${allHaveId}`); // true
// IoT场景:系统状态检查
function checkSystemStatus(sensorList: Sensor[]): string {
if (sensorList.length === 0) {
return "系统无传感器";
}
if (sensorList.every((s: Sensor) => s.normal)) {
return "系统全部正常";
}
if (sensorList.some((s: Sensor) => s.normal === false && s.value > 80)) {
return "严重警报:检测到高危异常";
}
return "系统存在轻微异常";
}
console.log(checkSystemStatus(sensors));
【小结表格】
| 方法 | 作用 | 返回值 | 找不到时 |
|---|---|---|---|
indexOf(value, from?) |
查找元素索引 | number | -1 |
includes(value) |
判断是否包含 | boolean | - |
find(predicate) |
查找满足条件的元素 | T | undefined | undefined |
findIndex(predicate) |
查找满足条件的索引 | number | -1 |
some(predicate) |
是否有元素满足条件 | boolean | false(空数组) |
every(predicate) |
是否所有元素满足条件 | boolean | true(空数组) |
第四部分:数组高级方法(函数式风格)
4.1 map(映射转换)
let rawReadings: number[] = [23.5, 24.0, 22.8, 25.2];
// map:对每个元素进行转换,返回新数组
// 场景:原始ADC读数转换为实际温度值
let temperatures: number[] = rawReadings.map((reading: number) => {
return reading * 0.1 + 20; // 模拟转换公式
});
console.log(`转换后温度:${temperatures.join(", ")}`);
// 场景:设备ID生成设备名称
let deviceIds: number[] = [101, 102, 103];
let deviceNames: string[] = deviceIds.map((id: number) => {
return `SENSOR-${id.toString().padStart(3, "0")}`;
});
console.log(`设备名称:${deviceNames.join(", ")}`);
// 输出:SENSOR-101, SENSOR-102, SENSOR-103
// 带索引的map
let indexedNames: string[] = deviceIds.map((id: number, index: number) => {
return `[${index}] DEVICE-${id}`;
});
console.log(`${indexedNames.join("; ")}`);
4.2 filter(过滤)
interface DeviceStatus {
id: number;
name: string;
temperature: number;
online: boolean;
}
let allDevices: DeviceStatus[] = [
{ id: 1, name: "DEV-A", temperature: 25.0, online: true },
{ id: 2, name: "DEV-B", temperature: 85.0, online: true },
{ id: 3, name: "DEV-C", temperature: 30.0, online: false },
{ id: 4, name: "DEV-D", temperature: 90.0, online: true }
];
// filter:筛选满足条件的元素
// 场景:找出高温设备(>80度)
let highTempDevices: DeviceStatus[] = allDevices.filter((d: DeviceStatus) => {
return d.temperature > 80.0;
});
console.log(`高温设备数量:${highTempDevices.length}`);
highTempDevices.forEach((d: DeviceStatus) => {
console.log(` - ${d.name}: ${d.temperature}°C`);
});
// 场景:找出在线且正常的设备
let healthyDevices: DeviceStatus[] = allDevices.filter((d: DeviceStatus) => {
return d.online === true && d.temperature < 80.0;
});
console.log(`健康设备:${healthyDevices.map((d: DeviceStatus) => d.name).join(", ")}`);
// 场景:过滤掉无效数据
let readings: (number | null)[] = [23.5, null, 24.0, null, 25.5];
let validReadings: number[] = readings.filter((r): r is number => r !== null);
console.log(`有效读数:${validReadings.join(", ")}`);
4.3 reduce(归约)
let powerReadings: number[] = [120, 135, 128, 142, 130];
// reduce:将数组归约为单个值
// 语法:arr.reduce((累加器, 当前值, 当前索引) => 新累加器, 初始值)
// 场景:计算总功耗
let totalPower: number = powerReadings.reduce((sum: number, current: number) => {
return sum + current;
}, 0);
console.log(`总功耗:${totalPower}W`);
// 场景:计算平均值
let averagePower: number = powerReadings.reduce((sum: number, current: number) => {
return sum + current;
}, 0) / powerReadings.length;
console.log(`平均功耗:${averagePower.toFixed(1)}W`);
// 场景:找出最大值
let maxPower: number = powerReadings.reduce((max: number, current: number) => {
return current > max ? current : max;
}, 0);
console.log(`峰值功耗:${maxPower}W`);
// 场景:统计各类设备数量
interface Device {
id: number;
type: string;
}
let deviceList: Device[] = [
{ id: 1, type: "TEMP" },
{ id: 2, type: "HUMI" },
{ id: 3, type: "TEMP" },
{ id: 4, type: "LIGHT" },
{ id: 5, type: "TEMP" }
];
let typeCount: Record<string, number> = deviceList.reduce((acc: Record<string, number>, d: Device) => {
acc[d.type] = (acc[d.type] ?? 0) + 1;
return acc;
}, {} as Record<string, number>);
console.log(`设备统计:TEMP=${typeCount["TEMP"]}, HUMI=${typeCount["HUMI"]}, LIGHT=${typeCount["LIGHT"]}`);
4.4 forEach(遍历)
let sensorNames: string[] = ["温度传感器", "湿度传感器", "光照传感器"];
// forEach:遍历每个元素,无返回值
sensorNames.forEach((name: string, index: number) => {
console.log(`[${index}] 正在初始化:${name}`);
});
// IoT场景:批量发送指令
let deviceAddresses: number[] = [0x01, 0x02, 0x03, 0x04];
deviceAddresses.forEach((addr: number) => {
// 模拟发送读取指令
console.log(`向地址0x${addr.toString(16).padStart(2, "0")}发送读取指令`);
});
// 注意:forEach中不能使用break/continue
// 如需中途停止,请使用for循环
4.5 链式调用(filter + map + reduce 组合)
interface SensorData {
id: number;
type: string;
value: number;
timestamp: number;
}
let rawData: SensorData[] = [
{ id: 1, type: "TEMP", value: 25.5, timestamp: 1000 },
{ id: 2, type: "TEMP", value: 26.0, timestamp: 1001 },
{ id: 3, type: "HUMI", value: 60.0, timestamp: 1002 },
{ id: 4, type: "TEMP", value: 85.0, timestamp: 1003 },
{ id: 5, type: "TEMP", value: 24.5, timestamp: 1004 }
];
// 场景:计算过去一小时内温度传感器的平均温度(排除异常值>80)
let avgTemp: number = rawData
.filter((d: SensorData) => d.type === "TEMP") // 只取温度数据
.filter((d: SensorData) => d.value <= 80.0) // 排除异常值
.map((d: SensorData) => d.value) // 提取温度值
.reduce((sum: number, val: number, idx: number, arr: number[]) => {
return idx === arr.length - 1 ? (sum + val) / arr.length : sum + val;
}, 0);
console.log(`平均温度:${avgTemp.toFixed(2)}°C`);
// 场景:生成设备状态报告
interface DeviceReport {
deviceId: string;
status: string;
reading: number;
}
let reports: DeviceReport[] = rawData
.filter((d: SensorData) => d.type === "TEMP")
.map((d: SensorData): DeviceReport => {
return {
deviceId: `TEMP-${d.id}`,
status: d.value > 80.0 ? "ALERT" : "NORMAL",
reading: d.value
};
});
reports.forEach((r: DeviceReport) => {
console.log(`${r.deviceId}: ${r.status} - ${r.reading}°C`);
});
【小结表格】
| 方法 | 作用 | 返回值 | 修改原数组 |
|---|---|---|---|
map(callback) |
映射转换 | 新数组 | ❌ 否 |
filter(predicate) |
过滤筛选 | 新数组 | ❌ 否 |
reduce(callback, init) |
归约聚合 | 单个值 | ❌ 否 |
forEach(callback) |
遍历执行 | undefined | ❌ 否 |
第五部分:只读数组
5.1 readonly 修饰符
// readonly修饰符:数组内容不可修改
const DEVICE_TYPES: readonly string[] = ["LED", "RGB", "DIMMABLE", "SWITCH"];
// ❌ 编译错误:无法修改只读数组
// DEVICE_TYPES[0] = "OTHER";
// DEVICE_TYPES.push("NEW");
// DEVICE_TYPES.pop();
// DEVICE_TYPES.splice(0, 1);
// ✅ 允许的操作:读取
console.log(`支持的设备类型:${DEVICE_TYPES.join(", ")}`);
console.log(`类型数量:${DEVICE_TYPES.length}`);
// ✅ 允许的操作:非修改方法
let hasLed: boolean = DEVICE_TYPES.includes("LED"); // true
let index: number = DEVICE_TYPES.indexOf("RGB"); // 1
// ✅ 允许的操作:创建新数组
let upperTypes: string[] = DEVICE_TYPES.map((t: string) => t.toUpperCase());
5.2 ReadonlyArray 泛型
// ReadonlyArray<T>:另一种只读数组声明方式
const VOLTAGE_LEVELS: ReadonlyArray<number> = [110, 220, 380];
// 与readonly修饰符效果相同
// VOLTAGE_LEVELS.push(440); // ❌ 编译错误
// 常用于函数参数,防止函数修改传入的数组
function calculateAverage(readings: ReadonlyArray<number>): number {
// readings.push(999); // ❌ 编译错误,安全!
let sum: number = 0;
for (let i: number = 0; i < readings.length; i++) {
sum += readings[i];
}
return readings.length > 0 ? sum / readings.length : 0;
}
let temps: number[] = [23.5, 24.0, 22.8];
let avg: number = calculateAverage(temps); // 可以传入普通数组
console.log(`平均值:${avg.toFixed(2)}`);
// 从普通数组创建只读数组
let mutableArr: number[] = [1, 2, 3];
let readonlyArr: ReadonlyArray<number> = mutableArr;
// readonlyArr.push(4); // ❌ 编译错误
【小结表格】
| 声明方式 | 语法 | 用途 |
|---|---|---|
| readonly修饰符 | readonly T[] |
常量数组定义 |
| ReadonlyArray泛型 | ReadonlyArray<T> |
函数参数保护 |
| 禁止的操作 | push/pop/splice等修改方法 | - |
| 允许的操作 | 读取、遍历、非修改方法 | - |
第六部分:元组(Tuple)
6.1 元组声明与访问(通过索引,不能解构!)
元组是固定长度数组,每个位置有确定的类型:
// 元组声明:[类型1, 类型2, 类型3, ...]
let deviceInfo: [number, string, boolean] = [1001, "温度传感器-A", true];
// 索引: 0 1 2
// 类型: number string boolean
// 通过索引访问(类型已知)
let deviceId: number = deviceInfo[0]; // 1001,类型number
let deviceName: string = deviceInfo[1]; // "温度传感器-A",类型string
let isOnline: boolean = deviceInfo[2]; // true,类型boolean
console.log(`设备${deviceId}(${deviceName})在线状态:${isOnline}`);
// IoT场景:传感器数据点 [时间戳, 数值, 质量标志]
let dataPoint: [number, number, boolean] = [Date.now(), 25.5, true];
let timestamp: number = dataPoint[0];
let value: number = dataPoint[1];
let quality: boolean = dataPoint[2];
console.log(`[${timestamp}] 读数:${value},质量:${quality ? "良好" : "可疑"}`);
// ⚠️ ArkTS不支持元组解构
// ❌ 编译错误
// let [dId, dName, dStatus] = deviceInfo;
// ✅ 正确:通过索引逐个访问
let dId: number = deviceInfo[0];
let dName: string = deviceInfo[1];
let dStatus: boolean = deviceInfo[2];
console.log(`解构效果:${dId}, ${dName}, ${dStatus}`);
6.2 可选元素
// 可选元素语法:[类型1, 类型2, 类型3?]
// ?表示该元素可以不存在
// IoT场景:设备信息 [ID, 名称, 可选:最后通信时间戳]
let deviceWithTime: [number, string, number?] = [1001, "传感器-A"];
// 也可以提供可选元素
let deviceWithTime2: [number, string, number?] = [1002, "传感器-B", Date.now()];
// 访问可选元素需要检查
let lastComm: number | undefined = deviceWithTime[2];
if (lastComm !== undefined) {
console.log(`最后通信:${lastComm}`);
} else {
console.log("无通信记录");
}
// 多个可选元素
let sensorConfig: [string, number?, number?, boolean?] = ["TEMP"];
// 可以只提供部分可选元素
let sensorConfig2: [string, number?, number?, boolean?] = ["HUMI", 0, 100];
6.3 只读元组
// readonly修饰元组
const SENSOR_RANGE: readonly [number, number] = [0, 100]; // 量程0-100
// ❌ 编译错误:无法修改只读元组
// SENSOR_RANGE[0] = -50;
// SENSOR_RANGE.push(200); // 元组没有push方法
// 应用场景:设备配置常量
const DEVICE_CONFIG: readonly [string, number, boolean] = ["TEMP_SENSOR", 1000, true];
// [设备类型, 采样间隔(ms), 是否启用]
console.log(`设备类型:${DEVICE_CONFIG[0]}`);
console.log(`采样间隔:${DEVICE_CONFIG[1]}ms`);
console.log(`启用状态:${DEVICE_CONFIG[2]}`);
// 从函数返回多个值(元组方式)
function getDeviceStats(): [number, number, boolean] {
// 模拟获取设备统计
return [100, 99.5, true]; // [设备数, 在线率, 系统正常]
}
let stats: [number, number, boolean] = getDeviceStats();
console.log(`设备数:${stats[0]},在线率:${stats[1]}%,系统正常:${stats[2]}`);
⚠️ ArkTS 不支持元组解构:
let coords: [number, number, number] = [100, 200, 50]; // x, y, z
// ❌ 编译错误:ArkTS不支持解构赋值
// let [x, y, z] = coords;
// ✅ 正确:逐个索引访问
let x: number = coords[0];
let y: number = coords[1];
let z: number = coords[2];
console.log(`坐标:(${x}, ${y}, ${z})`);
【小结表格】
| 特性 | 语法 | 说明 |
|---|---|---|
| 元组声明 | [T1, T2, T3] |
固定长度,各位置类型确定 |
| 访问元素 | tuple[index] |
通过索引访问 |
| 可选元素 | [T1, T2?] |
末尾元素可省略 |
| 只读元组 | readonly [T1, T2] |
内容不可修改 |
| ⚠️ 不支持 | 解构赋值 | let [a,b]=tuple 编译错误 |
第七部分:ArkTS 数组限制(重要提醒)
7.1 空数组必须显式声明类型
// ❌ 编译错误:无法推断空数组类型
// let empty = [];
// ✅ 正确:显式声明类型
let emptyNumbers: number[] = [];
let emptyStrings: Array<string> = [];
let emptyDevices: Device[] = []; // Device是interface
替代方案:声明时赋予初始类型明确的元素
// 如果不确定内容,可以先声明类型再push
let readings: number[] = [];
readings.push(23.5); // 后续添加元素
7.2 不支持解构赋值
// ❌ 编译错误:ArkTS不支持数组解构
// let [a, b] = [1, 2];
// ❌ 编译错误:ArkTS不支持元组解构
// let device: [number, string] = [1001, "DEV-A"];
// let [id, name] = device;
// ✅ 正确:逐个索引访问
let arr: number[] = [1, 2];
let a: number = arr[0];
let b: number = arr[1];
let device: [number, string] = [1001, "DEV-A"];
let id: number = device[0];
let name: string = device[1];
7.4 禁止使用 any 和 unknown
// ❌ 编译错误:ArkTS禁止any类型
// let mixed: any[] = [1, "two", true];
// ❌ 编译错误:ArkTS禁止unknown类型
// let unknownArr: unknown[] = [];
// ✅ 正确:使用联合类型
let mixed: (number | string | boolean)[] = [1, "two", true];
// ✅ 正确:使用具体类型
interface DataPoint {
type: string;
value: number;
}
let dataPoints: DataPoint[] = [
{ type: "TEMP", value: 25.5 },
{ type: "HUMI", value: 60.0 }
];
测试题
题1:判断输出
let sensors: number[] = [22, 25, 28, 30];
sensors.push(32);
sensors.shift();
let result: number = sensors.reduce((a: number, b: number) => a + b, 0);
console.log(`${result}`);
问题:上述代码输出什么?
答案
输出:115
解析:
- 初始数组:
[22, 25, 28, 30] - push(32)后:
[22, 25, 28, 30, 32] - shift()后:
[25, 28, 30, 32] - reduce求和:
25 + 28 + 30 + 32 = 115
题2:判断输出
let devices: string[] = ["DEV-001", "DEV-002", "DEV-003", "DEV-004"];
let sliced: string[] = devices.slice(1, 3);
let spliced: string[] = devices.splice(1, 1);
console.log(`${devices.length},${sliced.length},${spliced.length}`);
问题:上述代码输出什么?
答案
输出:3,2,1
解析:
slice(1, 3):提取索引1到2的元素,返回["DEV-002", "DEV-003"],长度2,原数组不变splice(1, 1):从索引1删除1个元素,返回["DEV-002"],长度1- 原数组变为
["DEV-001", "DEV-003", "DEV-004"],长度3
题3:找错(ArkTS限制)
function processData(): void {
let data = []; // 第1处
data.push(100);
let [x, y] = [10, 20]; // 第2处
console.log(`${x},${y}`);
}
问题:找出2处编译错误并说明原因。
答案
| 位置 | 错误 | 原因 | 修正 |
|---|---|---|---|
| 第1处 | let data = [] |
空数组推断为never[],无法添加元素 |
let data: number[] = [] |
| 第2处 | let [x, y] = [10, 20] |
ArkTS不支持解构赋值 | let arr: number[] = [10, 20]; let x: number = arr[0]; let y: number = arr[1] |
题4:找错(类型问题)
let readings: any[] = [23.5, 24.0, 22.8]; // 第1处
let sensor: [number, string] = [1001, "TEMP"];
let [sid, stype] = sensor; // 第2处
问题:找出2处问题并说明原因。
答案
| 位置 | 错误 | 原因 | 修正 |
|---|---|---|---|
| 第1处 | any[] |
ArkTS禁止any类型 | let readings: number[] = [...] |
| 第2处 | let [sid, stype] = sensor |
ArkTS不支持元组解构 | let sid: number = sensor[0]; let stype: string = sensor[1] |
题5:编程题(温度数据分析)
场景:处理一批传感器温度读数,找出异常值并生成报告。
要求:
- 创建包含8个温度读数的数组(部分值>80表示异常高温)
- 使用
filter找出所有异常读数(value > 80) - 使用
map将异常读数转换为报警信息字符串:"警报:温度XX°C超过阈值" - 使用
some检查是否有异常 - 使用
every检查是否所有读数都有效(<100) - 输出报警信息和检查结果
参考答案
let temperatures: number[] = [25.5, 85.0, 26.0, 92.5, 24.8, 88.0, 25.2, 95.0];
// 找出异常读数
let abnormalTemps: number[] = temperatures.filter((t: number) => t > 80.0);
// 生成报警信息
let alerts: string[] = abnormalTemps.map((t: number) => {
return `警报:温度${t}°C超过阈值80°C`;
});
// 检查是否有异常
let hasAbnormal: boolean = temperatures.some((t: number) => t > 80.0);
// 检查是否都有效(<100)
let allValid: boolean = temperatures.every((t: number) => t < 100.0);
// 输出结果
console.log(`是否有异常:${hasAbnormal}`);
console.log(`是否全部有效(<100):${allValid}`);
console.log(`异常读数数量:${abnormalTemps.length}`);
console.log("--- 报警信息 ---");
alerts.forEach((alert: string) => {
console.log(alert);
});
数组操作速查表
| 操作类别 | 方法 | 语法 | 返回值 | 修改原数组 |
|---|---|---|---|---|
| 声明 | 类型[] | let arr: number[] = [] |
- | - |
| Array<类型> | let arr: Array<number> = [] |
- | - | |
| 空数组 | let arr: string[] = [] |
- | - | |
| 增删 | push | arr.push(item1, item2) |
新长度 | ✅ |
| pop | arr.pop() |
被删元素/undefined | ✅ | |
| unshift | arr.unshift(item1, item2) |
新长度 | ✅ | |
| shift | arr.shift() |
被删元素/undefined | ✅ | |
| splice | arr.splice(start, deleteCount) |
被删元素数组 | ✅ | |
| concat | arr.concat(other) |
新数组 | ❌ | |
| slice | arr.slice(start?, end?) |
子数组 | ❌ | |
| 查找 | indexOf | arr.indexOf(value) |
number | ❌ |
| includes | arr.includes(value) |
boolean | ❌ | |
| find | arr.find(predicate) |
T/undefined | ❌ | |
| findIndex | arr.findIndex(predicate) |
number | ❌ | |
| some | arr.some(predicate) |
boolean | ❌ | |
| every | arr.every(predicate) |
boolean | ❌ | |
| 函数式 | map | arr.map(callback) |
新数组 | ❌ |
| filter | arr.filter(predicate) |
新数组 | ❌ | |
| reduce | arr.reduce(callback, init) |
单个值 | ❌ | |
| forEach | arr.forEach(callback) |
undefined | ❌ | |
| 只读 | readonly | readonly T[] |
- | - |
| ReadonlyArray | ReadonlyArray<T> |
- | - | |
| 元组 | 声明 | [T1, T2, T3] |
- | - |
| 可选 | [T1, T2?] |
- | - |
ArkTS 限制速查
| 限制 | 说明 | 替代方案 |
|---|---|---|
| ⚠️ 空数组类型 | 必须显式声明类型,否则推断为never[] |
let arr: number[] = [] |
| ⚠️ 解构赋值 | 不支持数组/元组解构 | 逐个索引访问 |
| ⚠️ any类型 | 完全禁止 | 使用联合类型或具体类型 |
| ⚠️ unknown类型 | 完全禁止 | 使用具体类型 |

浙公网安备 33010602011771号