一、ArkTS语言介绍

ArkTS是HarmonyOS应用的默认开发语言,在typescript基础上做了扩展,保持typescript的基本风格。旨在为开发者提供更高效、更安全的鸿蒙应用开发体验。

所以目前对于想要接触HarmonyOS应用开发的同学来说,学习ArkTS是必经之路。

在正式进入HarmonyOS开发之前,我们需要先熟悉一下ArkTS语言的语法。本文的讲解顺序及内容参考华为官方提供的指南,所以在学习过程中有不明白的地方,也可以直接去参考官方给出的文档,也欢迎大家给我提建议。

指南:ArkTS语言介绍-学习ArkTS语言-基础入门 - 华为HarmonyOS开发者

二、基本知识

2.1 基本知识

2.1.1 声明

声明也就是给数据起个"名字"。

想象一下生活中的场景:

  • 你养了一只宠物,给它起名叫"小白"

  • 你家住在某个小区,有个门牌号

  • 你有自己的身份证号

在编程中,声明就是做类似的事情:给数据起个名字,方便后续使用

ArkTS通过声明引入变量、常量、类型和函数。

2.1.1.1 变量的定义

变量:可以变的"盒子"

变量就像一个有名字的纸箱:你可以往里面放东西,你还可以把里面的东西换成别的,但纸箱的名字不变。

定义语法:

let 变量名: 类型 = 初始值;

示例:

let hi: string = 'hello'; // 声明变量hi

hi = 'Hello HarmonyOS'; // 修改变量的值

第一行代码,定义了一个变量hi,并定义初值为hello

第二行代码,将变量hi的值改为了Hello HarmonyOS

2.1.1.2 常量的定义

常量:一次定型的"雕塑"

常量就像用水泥浇铸的雕塑:制作时可以塑形(初始化),但是一旦凝固,就不能再改变,会一直保持原来的样子。

通过const关键字定义常量。常量的值只能被赋值一次。若试图对常量重新赋值会造成编译时错误。

const hello: string = 'hello'; // 常量的定义
2.1.1.3 自动类型推断

如果我们在声明变量/常量的时候就已经给了初值,就不需要显式地指定常量/变量对应的类型。ArkTS会自动推断其类型。

正如在2.1.1.1和2.1.1.2小节中举的例子,我们并没有显式地定义变量hi和常量hello的类型,但是ArkTS会自动地将他们定义为string。

2.1.2 类型
2.1.2.1 number类型

ArkTS提供number类型,任何整数和浮点数都可以被赋给此类型的变量。也就是说ArkTS的number类型是可以表达各种数字的。这和C、JAVA、Cangjie等语言不同,这些语言会将数字细分为具体的几种类型。

数字字面量包括整数字面量和十进制浮点数字面量(可以理解为包含小数点的小数,并且是以我们日常使用的十进制方式写的)。

整数字面量包括以下类别:

  • 十进制整数,由数字序列组成。例如:0、117、-345。
  • 十六进制整数,以0x(或0X)开头,包含数字(0-9)和字母a-f或A-F。例如:0x1123、0x00111、-0xF1A7。
  • 八进制整数,以0o(或0O)开头,只能包含数字(0-7)。例如:0o777。
  • 二进制整数,以0b(或0B)开头,只能包含数字0和1。例如:0b11、0b0011、-0b11。

浮点数字面量包括以下部分:

  • 十进制整数,可为有符号数(前缀为“+”或“-”)。
  • 小数点(“.”)。
  • 小数部分(由十进制数字字符串表示)。
  • 指数部分,以“e”或“E”开头,后跟有符号(前缀为“+”或“-”)或无符号整数。

我们可以看一下以下示例(示例来源于官方文档):

let n1 = 3.14;
let n2 = 3.141592;
let n3 = 0.5;
let n4 = 1e2;

function factorial(n: number): number {
  if (n <= 1) {
    return 1;
  }
  return n * factorial(n - 1);
}

factorial(n1)  //  7.660344000000002
factorial(n2)  //  7.680640444893748
factorial(n3)  //  1
factorial(n4)  //  9.33262154439441e+157

在上方示例中,首先定义了四个数字变量:n1、n2、n3、n4,这边要说明的是,n4使用了科学计数法,1e2的其实就等价于1×10²=100。

然后接下来,我们定义了一个递归函数来计算阶乘(factorial):

function factorial(n: number): number {
  if (n <= 1) {
    return 1;
  }
  return n * factorial(n - 1);
}

阶乘的数学符号是!,比如说5的阶乘就是5! = 5×4×3×2×1 = 120。而示例中的factorial函数就是按照这个规律计算的。当n <= 1时,阶乘结果就是1。

接着我们来观察一下计算结果:

factorial(3.14)  // 返回 7.660344000000002
factorial(3.141592)  // 返回 7.680640444893748

不难发现,以上两行代码是想试图去计算π的阶乘。但是通过对比可以发现,这两个得到的结果不同,由此我们可以得知,浮点数精度对计算是有影响的。

factorial(0.5)  // 返回 1

上面这行代码,是将n3=0.5作为参数传入函数。也就是试图计算0.5的阶乘。而在函数的设计中,我们设计了if判断,当n <= 1的时候,返回值为1。所以我们得到的结果也就是1。

factorial(100)  // 返回 9.33262154439441e+157

最后这个例子展示了对大数的计算。

number类型在表示大整数(即超过-9007199254740991~9007199254740991)时会造成精度丢失。在开发时可以按需使用BigInt类型来确保精度:

let bigInt: BigInt = BigInt('999999999999999999999999999999999999999999999999999999999999');
console.info('bigInt:' + bigInt.toString());
2.1.2.2 boolean类型

boolean类型由true和false两个逻辑值组成。

通常在条件语句中使用boolean类型的变量,例子如下:

let isDone: boolean = false;

// ...

if (isDone) {
  console.info('Done!');
}
2.1.2.3 string类型

string类型代表字符序列,可以使用转义字符(比如下方案例中的\n,代表换行)来表示字符。

字符串字面量由单引号(')或双引号(")之间括起来的零个或多个字符组成。字符串字面量还有一特殊形式,是用反向单引号(`)括起来的模板字面量。

示例:

let s1 = 'Hello, world!\n';
let s2 = 'this is a string';
let a = 'Success';
let s3 = `The result is ${a}`;
2.1.2.4 void类型

void类型用于指定函数没有返回值。

此类型只有一个值,同样是void。由于void是引用类型,因此它可以用于泛型类型参数。

class Class<T> {
  //...
}
let instance: Class<void>;
2.1.2.5 Object类型

Object类型是所有引用类型的基类型。任何值,包括基本类型的值,都可以直接被赋给Object类型的变量(基本类型值会被自动装箱)。

示例:

let o1: Object = 'Huawei';
let o2: Object = ['a', 'b'];
let o3: Object = 1;
let o4: object = [1, 2, 3];

自动装箱就是:当基本类型(如string、number)被赋值给Object类型时,ArkTS会自动把它们"包装"成对应的对象。

示例:

// 基本类型(原始值)
let str: string = 'hello';    // 只是一个字符串值
let num: number = 100;        // 只是一个数字值

// 赋值给Object时,会发生自动装箱
let obj1: Object = str;       // 字符串被包装成String对象
let obj2: Object = num;       // 数字被包装成Number对象
2.1.2.6 array类型

array类型,即数组,是由可赋值给数组声明中指定的元素类型的数据组成的对象。通俗地说,就算将多个相同类型的数据按顺序放在一起

数组可由数组复合字面量赋值。数组复合字面量是用方括号括起来的零个或多个表达式列表,每个表达式为数组中的一个元素。数组的长度由数组中元素的个数确定。数组中第一个元素的索引(下标)为0。

以下示例将创建包含三个元素的数组:

let series: string[] = ['Mate', 'Pura', 'Nova'];
2.1.2.7 enum类型

enum类型,即枚举类型,是预先定义的一组命名值的值类型,其中命名值又称为枚举常量。通俗地说,枚举是一组有名字的常量集合。它让代码更易读、更安全、更易维护。

使用枚举常量时必须以枚举类型名称为前缀。

示例:

enum ColorSet { Red, Green, Blue }
let c: ColorSet = ColorSet.Red;

我们通常也会使用常量表达式,用于显式设置枚举常量的值。示例:

enum ColorSet { White = 0xFF, Grey = 0x7F, Black = 0x00 }
let c: ColorSet = ColorSet.Black;
2.1.2.8 Union类型

Union类型,即联合类型,是由多个类型组合成的引用类型。联合类型包含了变量可能的所有类型。用竖线|连接。它表示"这个变量可以是A类型,也可以是B类型,还可以是C类型..."

class Cat {
  name: string = 'cat';
  // ...
}
class Dog {
  name: string = 'dog';
  // ...
}
class Frog {
  name: string = 'frog';
  // ...
}
type Animal = Cat | Dog | Frog | number | string | null | undefined;
// Cat、Dog、Frog是一些类型(类或接口)

let animal: Animal = new Cat();
animal = new Frog();
animal = 42;
animal = 'dog';
animal = undefined;
// 可以将类型为联合类型的变量赋值为任何组成类型的有效值

可以使用不同机制获取联合类型中的特定类型值。示例:

class Cat { sleep () {}; meow () {} }
class Dog { sleep () {}; bark () {} }
class Frog { sleep () {}; leap () {} }

type Animal = Cat | Dog | Frog;

function foo(animal: Animal) {
  if (animal instanceof Frog) {  // 判断animal是否是Frog类型
    animal.leap();  // animal在这里是Frog类型,这里确定是Frog,可以调用leap方法
  }
  animal.sleep(); // Animal具有sleep方法,所有动物都有sleep方法,可以直接调用
}

如果刚入门的朋友读到这边感觉难以理解代码的话,可以暂时先跳过,或者询问AI辅助理解一下,后续我们会具体讲解相关内容。

2.1.2.9 Aliases类型

Aliases类型为匿名类型(如数组、函数、对象字面量或联合类型)提供名称,或为已定义的类型提供替代名称。

简单理解,就像给类型起个"外号",让复杂的类型有一个简单好记的名字。

举几个例子:

例子1:给复杂类型起别名(二维数组示例)

// 定义一个"二维数字数组"类型,给它起名叫Matrix(矩阵)
type Matrix = number[][];

// 使用Matrix类型创建游戏棋盘
const gameBoard: Matrix = [
  [1, 0],  // 第一行
  [0, 1]   // 第二行
];

针对上面的例子,我们可以直观地理解一下:

  • 当没有别名时:const board: number[][] = ...(当我们阅读代码的时候,很难直接看出这个究竟是什么东西)
  • 有别名时:const board: Matrix = ...(我们可以很清晰地理解到,这是一个矩阵/表格)

例子2:给函数类型起别名(让函数"有名字")

// 给"一个函数,接收字符串和数字,返回字符串"这种类型起名为Handler
type Handler = (s: string, no: number) => string;

// 创建一个符合Handler类型的函数
const repeatString: Handler = (str, times) => {
  return str.repeat(times);
};

console.info(repeatString('abc', 3)); // 输出:'abcabcabc'

例子3:泛型函数类型别名

// 定义一个"判断函数"的类型模板
// T是占位符,表示"任意类型"
type Predicate<T> = (x: T) => boolean;

// 创建判断数字是否为偶数的函数
const isEven: Predicate<number> = (num) => num % 2 === 0;

// 创建判断字符串是否为空的函数
const isEmpty: Predicate<string> = (str) => str.length === 0;

Predicate<T>就像一个函数模板,把T换成具体类型,就得到具体的函数类型。

例子4:Union类型别名

// 定义一个"可能是对象,也可能是null"的类型
type NullableObject = Object | null;

class Cat {}  // 创建一个猫类

// 可以赋值一个对象
let animalData: NullableObject = new Cat();

// 也可以赋值null
let emptyData: NullableObject = null;
2.1.3 运算符

想象一下,在数学课中:

  • 你要比较两个数谁大:用比较符号(>、<)
  • 你要计算两个数的和:用加号(+)
  • 你要判断一个条件是否成立:用逻辑符号(与、或、非)

在编程中,运算符就是这些符号,它们让数据之间可以进行各种操作。

2.1.3.1 运算符概述

ArkTS的运算符就像一套完整的工具箱,每个工具有特定的用途:

运算符类别

主要作用

通俗比喻

赋值运算符

给变量"装"数据

往杯子里倒水

比较运算符

比较两个值的关系

比身高、比成绩

算术运算符

数学计算

加减乘除

位运算符

二进制位操作

开关灯、电路控制

逻辑运算符

逻辑判断

与、或、非的逻辑关系

instanceof

检查对象类型

判断是猫还是狗

2.1.3.2 赋值运算符

赋值运算符=,使用方式如x=y。也就是将y的值赋给x。

赋值运算符就像给杯子倒水

  • =表示"把右边的水倒进左边的杯子",也就是将右边的值赋给左边。
  • 复合赋值运算符可以理解为"先倒水,再搅拌"
let x = 5;     // 把5装进x这个"杯子"里
let y = 10;    // 把10装进y这个"杯子"里
let z = x;     // 把x杯子里的水倒进z杯子

复合赋值:先计算再赋值

复合赋值运算符将赋值与运算符组合在一起,例如:a += b 等价于 a = a + b,其中的 += 即为复合赋值运算符。复合赋值运算符是快捷操作,让代码更简洁。

复合赋值运算符包括:+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、|=、^=。

let a = 5;
let b = 3;

// 传统写法
a = a + b;   // a = 5 + 3 = 8

// 复合赋值写法
a += b;      // 等价于 a = a + b
2.1.3.3 比较运算符

运算符

说明

示例

结果

===

严格相等(会判断值和类型是否都相等)

5 === 5

true

!==

严格不相等

5 !== '5'

true

==

相等(可类型转换)

5 == '5'

true

!=

不相等(可类型转换)

5 != '5'

false

>

大于

10 > 5

true

>=

大于等于

5 >= 5

true

<

小于

3 < 5

true

<=

小于等于

5 <= 5

true

这边单独讲解一下,===与==的区别:

// ==只比较目标的值相等
console.info(String(null == undefined)); // true
// ===比较目标的值和类型都相等
console.info(String(null === undefined)); // false

双等号 ==值相等即可,会尝试类型转换再比较。就像"1斤棉花"和"1斤铁"比较重量。

三等号 ===值和类型都相等,不会进行类型转换,就像比较"1斤棉花"和"1斤铁",不仅要重量一样,材质也要一样。

2.1.3.4 算术运算符

一元运算符包括:-、+、--、++。

二元运算符列举如下:

运算符 说明
+ 加法
- 减法
* 乘法
/ 除法
% 除法后余数
2.1.3.5 位运算符

算术复合赋值运算符(5个)

运算符

等价写法

说明

+=

a = a + b

加法赋值

-=

a = a - b

减法赋值

*=

a = a * b

乘法赋值

/=

a = a / b

除法赋值

%=

a = a % b

取余赋值

位运算复合赋值运算符(6个)

运算符

等价写法

说明

<<=

a = a << b

左移赋值

>>=

a = a >> b

算术右移赋值

>>>=

a = a >>> b

逻辑右移赋值

&=

a = a & b

按位与赋值

|=

 a = a | b

按位或赋值

^=

a = a ^ b

按位异或赋值

2.1.3.6 逻辑运算符

逻辑运算符用于布尔值(true/false)的逻辑运算,就像生活中的"与、或、非"。

运算符 说明
a && b 逻辑与
a || b 逻辑或
! a 逻辑非
2.1.3.7 instanceof运算符

instanceof运算符用于在运行时检查一个对象是否是指定类或其子类的实例。我们在2.1.2.8的示例中就曾用到过,用于判断animal是否是Frog类型。

通俗点说,instanceof运算符就像身份证识别器,用来检查一个对象是否属于某个类(或其子类)。

基本用法:

对象 instanceof 类

如果对象是该类或其子类的实例,返回true,否则返回false

示例:

obj instanceof className

返回值类型为boolean。

如果obj是className类或其子类的实例,则返回值为true;否则,返回值为false。

class Person {}
const person = new Person();
if ((person instanceof Person)) {
  console.info('true'); // true
}

class Animal {}
class Bird extends Animal {}
const bird = new Bird();
if (bird instanceof Animal) {
  console.info('true'); // true
}
2.1.4 语句

语句:程序的"动作指令"

想象一下做菜的步骤:

  • 如果鸡蛋熟了 → 关火(条件判断)

  • 重复搅拌鸡蛋 → 直到均匀(循环)

  • 打鸡蛋、放盐、加热(顺序执行)

在编程中,语句就是程序执行的"动作指令",告诉计算机一步步该做什么。

2.1.4.1 if语句

if语句:编程中的"如果...就..."。

if语句用于需要根据逻辑条件执行不同语句的场景。当逻辑条件为真时,执行对应的一组语句,否则执行另一组语句(如果有的话)。

else部分也可以包含if语句。

示例:

if (条件) {
  // 条件为真时执行的代码
} else if (其他条件) {
  // 其他条件为真时执行的代码
} else {
  // 以上条件都不满足时执行的代码
}

示例:成绩评级

let score = 85;

if (score >= 90) {
  console.info('优秀');
} else if (score >= 80) {
  console.info('良好');  // 会执行这个
} else if (score >= 60) {
  console.info('及格');
} else {
  console.info('不及格');
}

条件表达式可以是任何类型,非boolean类型会进行隐式类型转换:

// 字符串:非空字符串为true,空字符串为false
let message = 'Hello';
if (message) {  // message不为空,为true
  console.info(message);  // 输出: Hello
}

// 数字:非0为true,0为false
let count = 3;
if (count) {  // 3不为0,为true
  console.info(`数量: ${count}`);
}

// 直接使用属性判断
let name = 'World';
if (name.length > 0) {  // 判断长度是否大于0
  console.info(`你好, ${name}`);
}
2.1.4.2 switch语句

switch语句:多重选择的"分叉路口",就像选择题,根据不同的选项执行不同的操作。

使用switch语句执行与switch表达式值匹配的代码块。

示例:

switch (表达式) {
  case 值1:
    // 当表达式等于值1时执行
    break;  // 跳出switch
  case 值2:
  case 值3:  // 多个case可以合并
    // 当表达式等于值2或值3时执行
    break; // 可省略
  default:
    // 以上都不匹配时执行
}

如果switch表达式的值等于某个label的值,则执行相应的语句。

如果没有任何一个label值与表达式值相匹配,并且switch具有default子句,那么程序会执行default子句对应的代码块。

break语句(可选的)允许跳出switch语句并继续执行switch语句之后的语句。

如果没有break语句,则执行switch中的下一个label对应的代码块。

示例:

let day = 3;  // 假设1-7代表周一到周日
let schedule = '';

switch (day) {
  case 1:
  case 2:
  case 3:
  case 4:
  case 5:
    schedule = '工作日,上班';
    break;
  case 6:
    schedule = '周六,休息';
    break;
  case 7:
    schedule = '周日,休息';
    break;
  default:
    schedule = '无效的日期';
}

console.info(schedule);  // 输出: 工作日,上班

注意break的作用:

let fruit = '苹果';
let price = 0;

switch (fruit) {
  case '苹果':
    price = 5;
    console.info('苹果5元/斤');
    // 这里没有break,会继续执行下面的case!
  case '香蕉':
    price = 3;
    console.info('香蕉3元/斤');
    break;
  case '橙子':
    price = 4;
    console.info('橙子4元/斤');
    break;
}

// 会输出两行:
// 苹果5元/斤
// 香蕉3元/斤
// 但price最终是3,这不是我们想要的!
2.1.4.3 条件表达式

条件表达式根据第一个表达式的布尔值来返回其他两个表达式之一的结果。条件表达式就像if-else的快捷方式,特别适合简单的条件判断。

基本结构:

条件 ? 值1 : 值2
// 如果条件为真 → 返回 值1
// 否则 → 返回 值2

示例:判断成绩是否合格

let score = 75;
let result = score >= 60 ? '合格' : '不合格';
console.info(result);  // 输出: 合格

如果条件的值为真值(转换后为true的值),则使用值1作为该表达式的结果;否则,使用值2作为该表达式的结果。

let message = Math.random() > 0.5 ? 'Valid' : 'Failed';

condition如果是非bool值则会进行隐式转换。

    console.info('a' ? 'true' : 'false'); // true
    console.info('' ? 'true' : 'false'); // false
    console.info(1 ? 'true' : 'false'); // true
    console.info(0 ? 'true' : 'false'); // false
    console.info(null ? 'true' : 'false'); // false
    console.info(undefined ? 'true' : 'false'); // false
2.1.4.4 for语句

for循环就像数数,重复执行特定次数的操作。

for语句会被重复执行,直到循环退出语句值为false。

示例:

for ([init]; [condition]; [update]) {
  statements
}

for语句的执行流程如下:

  1. 执行init表达式(如有)。此表达式通常初始化一个或多个循环计数器。
  2. 计算condition。如果它为真值(转换后为true的值),则执行循环主体的语句。如果它为假值(转换后为false的值),则for循环终止。
  3.  执行循环主体的语句。
  4. 如果有update表达式,则执行该表达式。
  5.  返回步骤2。

示例:计算累加

let sum = 0;
for (let i = 1; i <= 10; i++) {
  sum += i;  // 累加1到10
}
console.info(`1到10的和: ${sum}`);  // 输出: 55
2.1.4.5 for-of语句

for-of循环:遍历集合的"简单方式"

for-of循环专门用于遍历可迭代对象(数组、字符串、Set、Map等),比传统for循环更简洁。

示例如下:

for (let 元素 of 可迭代对象) {
  // 使用元素
}

示例1:遍历字符串

let text = 'Hello';
for (let ch of text) {
  console.info(ch);  // 依次输出: H, e, l, l, o
}

示例2:遍历不同类型的可迭代对象

// 1. 遍历数组
let colors = ['红', '绿', '蓝'];
for (let color of colors) {
  console.info(`颜色: ${color}`);
}

// 2. 遍历字符串的每个字符
let message = '你好世界';
for (let char of message) {
  console.info(char);  // 你, 好, 世, 界
}
2.1.4.6 while语句

while循环:条件满足就一直做

只要condition为真值(转换后为true的值),while语句就会执行statements语句。示例如下:

while (条件) {
  // 循环体
}

示例:计算累加

let n = 1;
let sum = 0;

while (n <= 5) {
  sum += n;  // 累加1到5
  n++;       // 更新条件
}

console.info(`1到5的和: ${sum}`);  // 输出: 15
2.1.4.7 do-while语句

do-while循环:先做一次,再看条件。先执行,后判断,保证循环体至少执行一次。

如果condition的值为真值(转换后为true的值),那么statements语句会重复执行。示例如下:

do {
  // 循环体
} while (条件);

示例:

let i = 0;
do {
  i += 1;
} while (i < 10)
2.1.4.8 break语句

break语句:紧急"退出"

break语句用于立即退出循环或switch,就像紧急出口按钮。

使用break语句可以终止循环语句或switch。

示例:

let x = 0;
while (true) {
  x++;
  if (x > 5) {
    break;
  }
}

如果break语句后带有标识符,则将控制流转移到该标识符所包含的语句块之外。

示例:

let x = 1;
label: while (true) {
  switch (x) {
    case 1:
      // statements
      break label; // 中断while语句
  }
}
2.1.4.9 continue语句

continue语句:跳过这一次

continue语句用于跳过当前循环迭代,直接进入下一次循环。

continue语句会停止当前循环迭代的执行,并将控制传递给下一次迭代。

示例:

for (let i = 0; i < 5; i++) {
  if (i % 2 === 0) {  // 如果i是偶数
    continue;  // 跳过这次循环
  }
  console.info(i);  // 输出: 1, 3
}
2.1.4.10 throw和try语句

异常处理:程序的"急救中心"

异常处理就像保险机制,当程序出现意外时,能够优雅地处理而不崩溃。

throw语句用于抛出异常或错误:

throw new Error('this error') // 抛出一个错误

try-catch用于捕获和处理异常,防止程序崩溃。

try {
  // 可能发生异常的语句块
} catch (e) {
  // 异常处理
}

下面的示例中throw和try语句用于处理除数为0的错误:

class ZeroDivisor extends Error {}

function divide (a: number, b: number): number {
  if (b == 0) {
    throw new ZeroDivisor();
  }
  return a / b;
}

function process (a: number, b: number) {
  try {
    let res = divide(a, b);
    console.info('result: ' + res);
  } catch (x) {
    console.error('some error');
  }
}

支持finally语句:

finally:无论是否发生异常都会执行,常用于清理工作。

function processData(s: string) {
  let error: Error | null = null;

  try {
    console.info('Data processed: ' + s);
    // ...
    // 可能发生异常的语句
    // ...
  } catch (e) {
    error = e as Error;
    // ...
    // 异常处理
    // ...
  } finally {
    // 无论是否发生异常都会执行的代码
    if (error != null) {
      console.error(`Error caught: input='${s}', message='${error.message}'`);
    }
  }
}

如果在学习过程中遇到任何问题,欢迎在评论区留言交流。

后续我将持续更新更多HarmonyOS开发教程,涵盖从基础到进阶的各个知识点,敬请关注!

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐