惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Azure Blog
Microsoft Azure Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Webroot Blog
Webroot Blog
腾讯CDC
The Last Watchdog
The Last Watchdog
博客园 - 司徒正美
H
Hacker News: Front Page
I
InfoQ
A
Arctic Wolf
H
Hackread – Cybersecurity News, Data Breaches, AI and More
H
Heimdal Security Blog
L
LINUX DO - 最新话题
T
Threat Research - Cisco Blogs
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
Security Latest
Security Latest
D
DataBreaches.Net
C
Check Point Blog
J
Java Code Geeks
www.infosecurity-magazine.com
www.infosecurity-magazine.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Attack and Defense Labs
Attack and Defense Labs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
L
Lohrmann on Cybersecurity
雷峰网
雷峰网
Vercel News
Vercel News
WordPress大学
WordPress大学
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Spread Privacy
Spread Privacy
Forbes - Security
Forbes - Security
阮一峰的网络日志
阮一峰的网络日志
Hacker News: Ask HN
Hacker News: Ask HN
大猫的无限游戏
大猫的无限游戏
I
Intezer
N
News and Events Feed by Topic
小众软件
小众软件
B
Blog RSS Feed
Help Net Security
Help Net Security
Google DeepMind News
Google DeepMind News
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 三生石上(FineUI控件)
S
Security @ Cisco Blogs
美团技术团队
Recent Announcements
Recent Announcements
Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main

博客园 - thammer

03 — std::vector 进阶篇 02 — 迭代器基础 01 — std::vector 基础篇 Day 17:Promise 基础 Day 16 - 读懂 TypeScript 声明文件(.d.ts) Day 15 - ArkTS 模块系统 Day 14 - ArkTS 错误处理 Day 13 - ArkTS 类型系统进阶 Day 12 - 泛型与阶段三总结 Day 11 - Interface 与类型契约 Day 10 - 继承与多态 Day 09 - Class 基础 Day 08 - 函数进阶与阶段总结 Day 07 - 函数类型与高阶函数 Day 06 - 函数基础 Day 05 - 数组和元组深入 Day 03 - 条件控制 Day 02 - 运算符与表达式 Day 01 - 变量与类型基础 Day 00 - 环境准备 C++虚函数 C++ 多继承 C++成员访问权限以及继承权限 C++ 成员初始化机制总结笔记
Day 04 - 循环与迭代
thammer · 2026-04-07 · via 博客园 - thammer

目标:掌握ArkTS的各种循环语句和数组迭代方法
预计时间:2-3小时


第一部分:for 循环

1.1 基本 for 循环

语法与C++相同for (初始化; 条件; 更新) { 循环体 }

// IoT场景:轮询5个传感器读数
for (let i: number = 0; i < 5; i++) {
  console.log(`传感器[${i}] 读数完成`);
}
// 输出:传感器[0] 读数完成 ... 传感器[4] 读数完成

// IoT场景:遍历设备列表
let devices: string[] = ["温度计-001", "湿度计-001", "烟雾-001", "灯-001"];

for (let i: number = 0; i < devices.length; i++) {
  console.log(`设备[${i}]: ${devices[i]}`);
}
// 输出:
// 设备[0]: 温度计-001
// 设备[1]: 湿度计-001
// 设备[2]: 烟雾-001
// 设备[3]: 灯-001

1.2 for 循环变体

倒序遍历

// IoT场景:倒计时关闭设备
for (let i: number = 5; i > 0; i--) {
  console.log(`设备将在 ${i} 秒后关闭`);
}
console.log("设备已关闭");

自定义步长

// IoT场景:每隔2个通道采样一次(共10个通道)
for (let channel: number = 0; channel < 10; channel += 2) {
  console.log(`采样通道 ${channel}`);
}
// 输出:采样通道 0, 2, 4, 6, 8

// IoT场景:以10%为步长调整亮度
for (let brightness: number = 0; brightness <= 100; brightness += 10) {
  console.log(`当前亮度:${brightness}%`);
}

多循环变量

⚠️ ArkTS支持:逗号运算符仅限 for 循环的初始化和更新表达式。

// ✅ 合法:for循环中使用逗号运算符
for (let i: number = 0, j: number = 10; i < j; i++, j--) {
  console.log(`i=${i}, j=${j}`);
}
// 输出:
// i=0, j=10
// i=1, j=9
// i=2, j=8
// i=3, j=7
// i=4, j=6

省略部分表达式

// 省略初始化和更新(等同于while)
let retryCount: number = 0;
for (; retryCount < 3;) {
  console.log(`第 ${retryCount + 1} 次重连...`);
  retryCount++;
}

1.3 嵌套 for 循环

// IoT场景:扫描 3栋楼 × 4个房间 的设备状态
for (let building: number = 1; building <= 3; building++) {
  for (let room: number = 1; room <= 4; room++) {
    console.log(`检查楼栋${building}-房间${room} 的设备状态`);
  }
}

// IoT场景:二维传感器矩阵读数(3行×3列)
let sensorMatrix: number[][] = [
  [25, 26, 24],
  [27, 25, 26],
  [24, 25, 27]
];

for (let row: number = 0; row < sensorMatrix.length; row++) {
  for (let col: number = 0; col < sensorMatrix[row].length; col++) {
    console.log(`传感器[${row}][${col}] 温度: ${sensorMatrix[row][col]}°C`);
  }
}

注意:嵌套层数越多,复杂度越高。实际开发中超过3层嵌套应考虑重构。


【第一部分小结】

变体 语法要点 典型场景
基本 for for (let i=0; i<n; i++) 已知次数的遍历
倒序 i--,条件 i > 0 倒计时、反向遍历
自定义步长 i += step 间隔采样、分页
多变量 let i=0, j=n; ...; i++, j-- 双指针、对称操作
嵌套 外层变量对内层可见 矩阵、多维结构遍历

第二部分:while 和 do-while

2.1 while 循环

语法与C++相同:先检查条件,再执行循环体。

// IoT场景:等待设备上线(未知重试次数)
let isConnected: boolean = false;
let attempts: number = 0;

while (!isConnected && attempts < 10) {
  console.log(`第 ${attempts + 1} 次尝试连接设备...`);
  attempts++;
  // 实际代码中这里会尝试真实连接
  if (attempts === 3) {
    isConnected = true; // 模拟第3次连接成功
  }
}

if (isConnected) {
  console.log(`连接成功,共尝试 ${attempts} 次`);
} else {
  console.log("连接失败,超过最大重试次数");
}
// IoT场景:持续读取传感器,直到读数稳定
let lastReading: number = -1;
let currentReading: number = 0;
let stableCount: number = 0;

while (stableCount < 3) {
  currentReading = 25; // 模拟读取传感器
  if (currentReading === lastReading) {
    stableCount++;
  } else {
    stableCount = 0;
  }
  lastReading = currentReading;
  console.log(`读数: ${currentReading}°C,稳定次数: ${stableCount}`);
}
console.log(`传感器读数已稳定: ${currentReading}°C`);

2.2 do-while 循环(至少执行一次)

与C++相同:先执行循环体,再检查条件。至少执行一次

// IoT场景:设备初始化(至少执行一次自检)
let initSuccess: boolean = false;
let initAttempts: number = 0;

do {
  initAttempts++;
  console.log(`第 ${initAttempts} 次设备自检...`);
  // 模拟自检逻辑
  if (initAttempts >= 2) {
    initSuccess = true;
  }
} while (!initSuccess && initAttempts < 5);

console.log(`设备自检完成,共自检 ${initAttempts} 次`);
// while vs do-while 的区别:
let condition: boolean = false;

// while:条件为false,一次都不执行
while (condition) {
  console.log("while:这行不会执行");
}

// do-while:条件为false,仍执行一次
do {
  console.log("do-while:这行会执行一次");
} while (condition);

2.3 while vs for 选择指南

// ✅ 已知循环次数 → 用 for
for (let i: number = 0; i < devices.length; i++) {
  console.log(`处理设备 ${i}`);
}

// ✅ 未知次数,等待条件 → 用 while
let deviceReady: boolean = false;
while (!deviceReady) {
  console.log("等待设备就绪...");
  // deviceReady = checkDevice();
}

// ✅ 至少执行一次 → 用 do-while
do {
  console.log("发送心跳包");
  // sendHeartbeat();
} while (isAlive());
场景 推荐 原因
已知循环次数 for 结构紧凑,循环变量作用域清晰
未知次数,先判断 while 条件驱动,可能一次不执行
至少执行一次 do-while 保证循环体至少运行一次
等待某个外部状态 while 条件更灵活

【第二部分小结】

循环类型 条件检查时机 最少执行次数 典型用途
while 执行前 0次 等待连接、轮询状态
do-while 执行后 1次 设备初始化、菜单交互
for 执行前 0次 已知次数遍历

第三部分:for-of 循环(推荐遍历数组)

3.1 基本用法

for-of 直接遍历数组元素值,无需手动管理索引,是遍历数组的推荐方式。

// IoT场景:遍历所有设备执行状态检查
let deviceNames: string[] = ["温度计-001", "湿度计-001", "烟雾-001", "灯-001"];

for (let device of deviceNames) {
  console.log(`检查设备: ${device}`);
}
// 输出:
// 检查设备: 温度计-001
// 检查设备: 湿度计-001
// 检查设备: 烟雾-001
// 检查设备: 灯-001
// IoT场景:字符串数组遍历
let deviceNames: string[] = ["温度计-001", "湿度计-001", "烟雾-001", "灯-001"];

for (let name of deviceNames) {
  console.log(`检查设备: ${name}`);
}

与普通 for 循环对比:

// 两种写法效果相同,for-of 更简洁
let readings: number[] = [23.5, 24.1, 22.8, 25.0];

// ✅ for-of:更简洁(不需要索引时推荐)
for (let reading of readings) {
  console.log(`读数: ${reading}°C`);
}

// 等效的 for 写法
for (let i: number = 0; i < readings.length; i++) {
  console.log(`读数: ${readings[i]}°C`);
}

3.2 需要索引时的写法

⚠️ ArkTS限制:不支持解构赋值,因此 for (let [index, device] of devices.entries()) 不合法

// ❌ 错误:ArkTS不支持解构赋值
// for (let [index, device] of devices.entries()) {
//   console.log(`${index}: ${device}`);
// }

// ✅ 方案一:改用普通 for 循环(最直接)
let deviceNames: string[] = ["温度计-001", "湿度计-001", "烟雾-001"];

for (let i: number = 0; i < deviceNames.length; i++) {
  console.log(`[${i}] ${deviceNames[i]}`);
}

// ✅ 方案二:for-of + 手动计数器
let index: number = 0;
for (let device of deviceNames) {
  console.log(`[${index}] ${device}`);
  index++;
}

结论:需要索引时,优先用普通 for 循环,不要尝试 entries() + 解构。


3.3 遍历字符串

for-of 也可以遍历字符串,逐个访问每个字符。

// IoT场景:解析设备ID格式(如 "D001")
let deviceId: string = "D001";

for (let char of deviceId) {
  console.log(`字符: ${char}`);
}
// 输出:
// 字符: D
// 字符: 0
// 字符: 0
// 字符: 1

// IoT场景:检查命令字符串是否只含数字和字母
let command: string = "CMD123";
let hasSpecialChar: boolean = false;

for (let char of command) {
  let code: number = char.charCodeAt(0);
  let isAlphaNum: boolean = (code >= 48 && code <= 57) ||   // 0-9
                            (code >= 65 && code <= 90) ||   // A-Z
                            (code >= 97 && code <= 122);    // a-z
  if (!isAlphaNum) {
    hasSpecialChar = true;
    break;
  }
}
console.log(`命令 "${command}" 含特殊字符: ${String(hasSpecialChar)}`);

【第三部分小结】

场景 推荐写法 备注
只需元素值 for (let item of arr) 最简洁
需要索引 普通 for 循环 ArkTS无法用解构
遍历字符串字符 for (let char of str) 逐字符访问

第四部分:break 和 continue

4.1 break(终止循环)

break 立即终止当前循环,跳到循环后的第一条语句。

// IoT场景:发现第一个超温传感器后立即告警并停止扫描
let temperatures: number[] = [25, 92, 28, 26];
let overTempIndex: number = -1;

for (let i: number = 0; i < temperatures.length; i++) {
  console.log(`扫描设备[${i}], 温度: ${temperatures[i]}°C`);
  if (temperatures[i] > 90) {
    overTempIndex = i;
    break;  // 找到超温设备,立即停止扫描
  }
}

if (overTempIndex !== -1) {
  console.log(`警告:设备[${overTempIndex}] 温度超限!`);
}

嵌套循环中的 break:只退出当前层循环。

// IoT场景:扫描楼层-房间矩阵,找到第一个故障设备后停止扫描当前楼层
for (let floor: number = 1; floor <= 3; floor++) {
  console.log(`--- 扫描第${floor}层 ---`);
  let floorDeviceIds: number[] = [101, 102, 103];
  for (let i: number = 0; i < floorDeviceIds.length; i++) {
    let deviceId: number = floorDeviceIds[i];
    if (floor === 2 && deviceId === 102) {
      console.log(`第${floor}层设备${deviceId}故障,停止扫描本层`);
      break;  // 只退出内层循环,外层继续
    }
    console.log(`  设备 ${deviceId} 正常`);
  }
}

4.2 continue(跳过当前迭代)

continue 跳过本次迭代的剩余语句,直接进入下一次迭代。

// IoT场景:批量发送指令,跳过离线设备
let statuses: string[] = ["online", "offline", "online", "error", "online"];
let successCount: number = 0;

for (let i: number = 0; i < statuses.length; i++) {
  if (statuses[i] !== "online") {
    console.log(`跳过设备[${i}](状态: ${statuses[i]})`);
    continue;  // 跳过非在线设备
  }
  
  // 只有 online 的设备才会执行到这里
  console.log(`向设备[${i}] 发送指令`);
  successCount++;
}

console.log(`成功发送指令给 ${successCount} 个设备`);

continueif 嵌套的等效写法对比:

// ✅ 使用 continue(扁平化代码,更清晰)
for (let status of statuses) {
  if (status !== "online") continue;
  console.log(`处理在线设备`);
}

// 等效但嵌套更深的写法
for (let status of statuses) {
  if (status === "online") {
    console.log(`处理在线设备`);
  }
}

4.3 带标签的 break(跳出多层循环)

当需要从嵌套循环内部直接跳出外层循环时,使用带标签的 break

// IoT场景:在楼层-房间-设备三层结构中,发现严重故障立即终止所有扫描
let found: boolean = false;
let foundFloor: number = 0;
let foundRoom: number = 0;

outerScan: for (let floor: number = 1; floor <= 3; floor++) {
  for (let room: number = 1; room <= 4; room++) {
    console.log(`扫描 ${floor}楼-${room}号房`);
    // 模拟:2楼3号房发现严重故障
    if (floor === 2 && room === 3) {
      found = true;
      foundFloor = floor;
      foundRoom = room;
      break outerScan;  // 直接跳出外层 outerScan 循环
    }
  }
}

if (found) {
  console.log(`严重故障:${foundFloor}楼-${foundRoom}号房,已终止全部扫描`);
}
// 对比:不带标签的break(只退出内层)
for (let floor: number = 1; floor <= 3; floor++) {
  for (let room: number = 1; room <= 4; room++) {
    if (floor === 2 && room === 3) {
      break;  // 只退出 room 循环,floor 循环继续
    }
  }
  console.log(`${floor}楼扫描完成`); // 仍会执行
}

⚠️ 提示:带标签的 break 对应 C++ 的 goto,但语义更明确、更安全。

标签使用规则

标签只能标记以下语句forwhiledo-whileswitch

// ✅ 正确:标签在 for 循环前面
outer: for (let i: number = 0; i < 3; i++) {
  break outer;
}

// ❌ 错误:标签后不是循环语句
label: {
  // 普通代码块,不能用 break label
}

break 只能跳出包含它的、被标签标记的语句

  • 不能跳入代码块
  • 不能跳出函数
  • 不能跳过变量初始化
// ❌ 错误:不能跳出函数
function test(): void {
  outer: for (let i: number = 0; i < 3; i++) {
    if (i === 1) {
      break outer;  // 这是可以的,在函数内部跳循环
    }
  }
}

// ❌ 错误:不能跳入另一个代码块
if (condition) {
  target: console.log("目标");  // 标签不能标记语句
}

【第四部分小结】

语句 作用范围 效果
break 当前循环层 立即终止当前循环
continue 当前循环层 跳过本次迭代,继续下一次
break label 指定标签的循环层 跳出到标签所在循环之外

第五部分:ArkTS 循环限制(重要提醒)

6.1 不支持 for...in(官方明确禁止)

ArkTS 官方规范明确禁止 for...in 语法。

// ❌ 错误:ArkTS不支持 for...in
// for (let key in someObject) {
//   console.log(key);
// }

// ✅ 替代方案一:直接访问已知属性
let deviceId: number = 1001;
let deviceName: string = "灯-001";
console.log(`id: ${deviceId}`);
console.log(`name: ${deviceName}`);

// ✅ 替代方案二:对数组用 for 循环(如果原本用 for...in 遍历数组索引)
let deviceNames: string[] = ["灯-001", "灯-002", "灯-003"];

// ❌ 用 for...in 遍历数组(ArkTS不支持,且有潜在风险)
// for (let index in deviceNames) {
//   console.log(deviceNames[index]);
// }

// ✅ 正确:用 for 循环或 for-of
for (let i: number = 0; i < deviceNames.length; i++) {
  console.log(`[${i}] ${deviceNames[i]}`);
}

for (let name of deviceNames) {
  console.log(name);
}

6.2 不支持解构赋值(entries() 不能解构)

ArkTS 明确不支持解构变量声明(数组解构和对象解构均不支持)。

let devices: string[] = ["灯-001", "灯-002", "灯-003"];

// ❌ 错误:ArkTS不支持数组解构
// for (let [index, device] of devices.entries()) {
//   console.log(`${index}: ${device}`);
// }

// ❌ 错误:ArkTS不支持对象解构
// let { id, name } = device;

// ✅ 替代方案一:用普通 for 循环(同时获得索引和值)
for (let i: number = 0; i < devices.length; i++) {
  console.log(`[${i}] ${devices[i]}`);
}

// ✅ 替代方案二:for-of + 手动计数器
let idx: number = 0;
for (let device of devices) {
  console.log(`[${idx}] ${device}`);
  idx++;
}

// ✅ 替代方案三:对象属性用点运算符访问
// 假设有一个设备对象
let deviceObj: object = { id: 1001, name: "灯-001" };
// 直接通过属性名访问,不能用解构
let devId: number = deviceObj.id;
let devName: string = deviceObj.name;
console.log(`设备: ${devId} - ${devName}`);

【第六部分小结】

限制 错误写法 替代方案
不支持 for...in for (let k in obj) 直接访问属性 / 用 for/for-of
不支持数组解构 let [a, b] = arr arr[0], arr[1]
不支持对象解构 let {id, name} = obj obj.id, obj.name
不支持解构迭代 for (let [i, v] of arr.entries()) 普通 for 循环

测试题

题1:判断输出(基础)

以下代码的输出结果是什么?

let total: number = 0;
for (let i: number = 1; i <= 5; i++) {
  if (i % 2 === 0) continue;
  total += i;
}
console.log(`total = ${total}`);
答案

total = 9

分析:只累加奇数:1 + 3 + 5 = 9。偶数(2、4)被 continue 跳过。


题2:判断输出(标签break)

以下代码的输出结果是什么?

outer: for (let i: number = 0; i < 3; i++) {
  for (let j: number = 0; j < 3; j++) {
    if (i + j >= 3) {
      break outer;
    }
    console.log(`i=${i}, j=${j}`);
  }
}
答案
i=0, j=0
i=0, j=1
i=0, j=2
i=1, j=0
i=1, j=1

分析:当 i=1, j=2 时,1+2=3 >= 3,执行 break outer,跳出外层循环。在此之前 i=0,j=0/1/2i=1,j=0/1 均被打印。


题3:找错题(ArkTS限制)

下面代码有几处 ArkTS 编译错误?指出并修正。

let values: number[] = [25, 92, 28];

// 错误1
for (let key in values) {
  console.log(key);
}

// 错误2
for (let [index, value] of values.entries()) {
  console.log(String(value));
}
答案

错误1:ArkTS 不支持 for...in
修正:改用 for (let i: number = 0; i < values.length; i++)

错误2:ArkTS 不支持解构赋值 [index, value]
修正:改用普通 for 循环并通过索引访问:

for (let i: number = 0; i < values.length; i++) {
  console.log(String(values[i]));
}

题4:编程题(设备轮询)

需求:实现一个设备状态轮询函数。

给定设备数组(每个设备包含 statuspowerWatts 属性),使用循环:

  1. 跳过状态为 "error" 的设备
  2. 统计在线设备(status === "online")的总功耗
  3. 发现功耗超过 2000W 时立即停止轮询并告警
  4. 返回总功耗、轮询设备数、是否告警
function pollDevices(devices: object[]): object {
  // 请在此实现
}
参考答案
function pollDevices(devices: object[]): object {
  let totalPower: number = 0;
  let polledCount: number = 0;
  let alarm: boolean = false;

  for (let device of devices) {
    if (device.status === "error") {
      continue;  // 跳过故障设备
    }

    polledCount++;
    if (device.status === "online") {
      totalPower += device.powerWatts;
    }

    if (totalPower > 2000) {
      alarm = true;
      break;  // 超过阈值立即停止
    }
  }

  return { totalPower: totalPower, polledCount: polledCount, alarm: alarm };
}

循环语句速查表

语句 语法 ArkTS支持 主要用途
for for (let i=0; i<n; i++) 已知次数遍历、需要索引
while while (cond) { } 未知次数、等待条件
do-while do { } while (cond) 至少执行一次
for-of for (let x of arr) 遍历数组元素(推荐)
for-in for (let k in obj) ArkTS禁止
解构迭代 for (let [i,v] of arr.entries()) ArkTS禁止
break break 终止当前循环
break label break label 跳出多层循环
continue continue 跳过当前迭代