在鸿蒙应用开发中,ArkTS** 作为主力开发语言,其高级数据类型是构建复杂功能的基础。掌握数组、枚举、联合这几种核心高级类型,能让你的代码更简洁、可读性更强、扩展性更优。今天就带大家从实际场景出发,吃透这些关键知识点,助力你高效开发鸿蒙应用。
一、枚举类型:给 “魔法数字” 起个 “好名字”
1. 为什么需要枚举?
开发中你是否遇到过这样的问题:代码里充斥着0、1、2这类 “魔法数字”,比如用0代表 “播放”、1代表 “暂停”、2代表 “停止”。过段时间再看代码,根本记不清这些数字的含义;团队协作时,新人更是需要反复询问才能理解。
枚举(Enum)就是为解决这个问题而生 —— 它用有意义的名称替代固定值,约定变量只能在一组预设范围内取值,让代码 “自解释”。
比如淘宝 APP 的主题色控制:直接写颜色编码#ff0f29、#ff7100不够直观,但用Red、Orange、Green来表示,任何人看代码都能瞬间明白对应的颜色含义。
2. 枚举的定义与使用(ArkTS 实战)
在 ArkTS 中,枚举通过enum关键字定义,默认值从0开始递增,也可手动指定自定义值。
(1)基础定义:默认值枚举
以 “音乐播放器状态” 为例,定义播放、暂停、停止三种状态:`
// 定义枚举类型
enum PlayerStatus {
Playing, // 默认值 0
Paused, // 默认值 1
Stopped // 默认值 2
}
@Entry
@Component
struct TestPage {
@State message: string = 'Hello World';
build() {
Column() {
// 字符串类型演示按钮
Button('枚举类型演示').onClick(() => {
// 使用枚举:变量类型指定为枚举,取值只能是枚举内的选项
let currentStatus: PlayerStatus = PlayerStatus.Playing;
// 打印验证:枚举值本质是数字,这里会输出 "当前状态值:0"
console.log(`当前状态值:${currentStatus}`);
})
}
}
}
(2)自定义值枚举
如果需要非连续的枚举值(比如与后端返回状态码对齐),可手动赋值:
// 自定义枚举值,与后端状态码保持一致
enum OrderStatus {
Pending = 10, // 待支付
Paid = 20, // 已支付
Shipped = 30, // 已发货
Delivered = 40 // 已送达
}
@Entry
@Component
struct TestPage {
@State message: string = 'Hello World';
build() {
Column() {
// 字符串类型演示按钮
Button('枚举类型演示').onClick(() => {
// 使用自定义值枚举
let myOrderStatus: OrderStatus = OrderStatus.Paid;
console.log(`订单状态值:${myOrderStatus}`); // 输出 "订单状态值:20"
})
}
}
}
(3)枚举的优势
- 可读性用
PlayerStatus.Playing替代0,代码逻辑一目了然; - 类型安全若给枚举变量赋值不在范围内(比如
currentStatus = 3),编译器会直接报错,避免非法值; - 可维护性若后续需要新增状态(如 “缓冲中”),只需在枚举中添加
Buffering,无需修改所有关联代码。
3. 枚举的常见应用场景
- 状态控制:如播放器状态、订单状态、登录状态;
- 固定选项:如性别(男 / 女 / 未知)、支付方式(微信 / 支付宝 / 银行卡);
- 配置项:如主题色、字体大小选项。
二、联合类型:让变量 “灵活多变”
1. 为什么需要联合类型?
常规变量只能有一种类型(比如let score: number只能存数字,let grade: string只能存字符串),但实际开发中常有 “变量需要存多种类型” 的场景。
比如 “考试成绩”:有的场景用分数(数字,如90)表示,有的场景用等级(字符串,如A)表示。若用常规类型,需要定义两个变量分别存储;而联合类型(Union)允许变量同时支持多种类型,让代码更灵活。
2. 联合类型的定义与使用(ArkTS 实战)
联合类型用|分隔多个类型,表示 “变量可以是类型 1,也可以是类型 2,还可以是类型 3...”。
(1)基础用法:多类型变量
以 “考试成绩” 为例,支持数字(分数)和字符串(等级)两种类型:
// 定义联合类型:score可以是number或string
let score: number | string;
@Entry
@Component
struct TestPage {
@State message: string = 'Hello World';
build() {
Column() {
// 字符串类型演示按钮
Button('联合类型演示').onClick(() => {
// 赋值为数字(分数)
score = 85;
console.log(`分数:${score}`); // 输出 "分数:85"
// 赋值为字符串(等级)
score = "B";
console.log(`等级:${score}`); // 输出 "等级:B"
})
}
}
}
(2)进阶用法:解决 “空值问题”
在 ArkTS 新版本中,变量默认不允许赋值为null(避免空指针异常)。但实际开发中,有些对象(如播放器组件、网络请求结果)初始化时可能暂时为空,此时可用联合类型结合null解决:
// 导入鸿蒙媒体组件
import { media } from '@kit.MediaKit';
@Entry
@Component
struct TestPage {
@State message: string = 'Hello World';
build() {
Column() {
// 字符串类型演示按钮
Button('联合类型演示').onClick(async () => {
// 联合类型:avPlayer可以是AVPlayer对象,也可以是null
let avPlayer: media.AVPlayer | null;
// 初始化前:赋值为null(合法)
avPlayer = null;
// 后续初始化完成后:赋值为AVPlayer对象
avPlayer = await media.createAVPlayer();
// 使用时需判断非空,避免报错
if (avPlayer !== null) {
avPlayer.play(); // 调用播放方法
}
})
}
}
}
(3)联合类型的注意事项
-
联合类型的变量只能使用所有类型共有的属性 / 方法:比如
number | string类型的变量,只能用toString()(数字和字符串都有该方法),不能用toFixed()(仅数字有); -
如需使用特定类型的方法,需先通过
typeof或类型断言缩小类型范围:`
let data: number | string = 100;
if (typeof data === "number") {
console.log(data.toFixed(2)); // 缩小为number类型,可调用toFixed()
}
三、数组类型:高效管理 “批量数据”
1. 为什么需要数组?
如果需要存储 10 个学生的姓名,用常规变量需要定义name1、name2...name10,不仅繁琐,还无法批量操作(如排序、查找)。
数组(Array)是连续的内存空间,专门用于存储批量数据,支持动态扩容和丰富的批量操作方法,是处理 “一组同类数据” 的最佳选择。
2. 数组的定义与使用(ArkTS 实战)
ArkTS 数组的定义有两种方式:类型[](简洁)和new Array()(灵活),数组下标从0开始。
(1)数组的两种定义方式
// 方式1:类型[] 定义(推荐,简洁)
// 字符串数组:存储学生姓名
let studentNames: string[] = ["张三", "李四", "王五"];
// 数字数组:存储学生成绩
let studentScores: number[] = [95, 88, 92];
// 方式2:new Array() 定义(适合指定初始长度)
// 定义长度为5的空数字数组(初始值为undefined)
let emptyArray: number[] = new Array(5);
(2)数组的核心操作
- 访问元素通过下标
数组[索引]访问,注意索引不能超出数组长度(否则返回undefined); - 修改元素直接给指定下标赋值;
- 动态扩容ArkTS 数组支持自动扩容,直接给超出当前长度的下标赋值即可;
- 批量操作借助数组 API(如
push、pop、find等)高效处理数据。
实战示例:
// 方式1:类型[] 定义(推荐,简洁)
// 字符串数组:存储学生姓名
let studentNames: string[] = ["张三", "李四", "王五"];
// 数字数组:存储学生成绩
let studentScores: number[] = [95, 88, 92];
// 方式2:new Array() 定义(适合指定初始长度)
// 定义长度为5的空数字数组(初始值为空)
let emptyArray: number[] = new Array(5);
@Entry
@Component
struct TestPage {
@State message: string = 'Hello World';
build() {
Column() {
// 字符串类型演示按钮
Button('联合类型演示').onClick(async () => {
// 1. 访问元素:获取第2个学生的姓名(下标1)
console.log(studentNames[1]); // 输出 "李四"
// 2. 修改元素:将第3个学生的成绩改为90
studentScores[2] = 90;
console.log(studentScores.toString()); // 输出 [95, 88, 90]
// 3. 动态扩容:给下标5赋值(原长度3,扩容后长度6)
studentNames[5] = "小丽";
console.log(studentNames.length.toString()); // 输出 6
console.log(studentNames.toString()); // 输出 ["张三", "李四", "王五", , , "小丽"]
// 4. 数组API:添加元素(push)、查找元素(find)
// 添加新学生姓名
studentNames.push("小亮");
console.log(studentNames.toString()); // 输出 ["张三", "李四", "王五", , , "小丽", "小亮"]
// 查找成绩≥90的学生(返回第一个符合条件的成绩)
const highScore = studentScores.find(score => score >= 90);
console.log(highScore?.toString()); // 输出 95
})
}
}
}
(3)数组的性能注意事项
- 避免频繁 “跨越式扩容”:比如给长度为 10 的数组直接赋值
array[1000] = 10,会导致数组长度骤增到 1001,中间大量位置为空,浪费内存; - 优先使用数组 API:
push(尾部添加)、pop(尾部删除)性能优于unshift(头部添加)、shift(头部删除),因为头部操作需要移动所有元素; - 类型一致性:尽量保证数组内元素类型统一(如
string[]只存字符串),避免any[](任意类型数组),否则会失去类型检查的优势。
四、高级数据类型的实战组合:打造简易音乐播放器
光说不练假把式,我们结合枚举、联合、数组,打造一个简易音乐播放器的 “状态管理模块”,看看这些高级类型如何协同工作。
import { media } from '@kit.MediaKit';
// 1. 用枚举定义播放器状态
enum PlayerStatus {
Idle = 0, // 空闲
Playing = 1, // 播放中
Paused = 2, // 暂停
Buffering = 3 // 缓冲中
}
// 2. 用数组存储播放列表(歌曲信息:名称+时长)
interface Song {
name: string;
duration: number; // 时长(秒)
}
const playList: Song[] = [
{ name: "《晴天》", duration: 256 },
{ name: "《七里香》", duration: 281 },
{ name: "《稻香》", duration: 293 }
];
// 3. 用联合类型定义播放器核心变量(支持null初始化)
let avPlayer: media.AVPlayer | null = null;
let currentStatus: PlayerStatus = PlayerStatus.Idle;
let currentIndex: number | null = null; // 当前播放歌曲的索引
@Entry
@Component
struct TestPage {
@State message: string = 'Hello World';
build() {
Column() {
// 字符串类型演示按钮
Button('实战演示').onClick(async () => {
// 5. 调用播放方法:播放第2首歌(索引1)
playSong(1);
// 输出:正在播放:《七里香》,时长:281秒
})
}
}
}
// 4. 播放方法:结合三种高级类型
async function playSong(index: number): Promise<void> {
// 校验索引合法性
if (index < 0 || index >= playList.length) {
console.error("无效的歌曲索引");
return;
}
// 初始化播放器(若未初始化)
if (avPlayer === null) {
avPlayer = await media.createAVPlayer();
}
// 更新状态和当前索引
currentStatus = PlayerStatus.Playing;
currentIndex = index;
// 模拟播放逻辑
const currentSong = playList[index];
console.log(`正在播放:${currentSong.name},时长:${currentSong.duration}秒`);
avPlayer.play(); // 调用播放器播放方法
}
五、总结与拓展
| 数据类型 | 核心作用 | 关键特性 | 典型应用场景 |
|---|---|---|---|
| 枚举(Enum) | 约束变量为固定常量集合 | 语义化、类型约束强、默认值规则 | 状态控制、固定分类(如颜色、权限) |
| 联合(Union) | 允许变量存储多种类型数据 | 灵活性高、需类型判断确保安全 | 多格式数据(如成绩)、对象初始化兼容 |
| 数组(Array) | 批量存储同类型数据 | 连续内存、动态扩容、下标访问 | 列表数据(如学生、商品)、算法实现 |
| 对象(Object) | 存储键值对形式的复杂数据 | 属性动态添加、类型灵活(可结合接口约束) | 复杂实体(如用户信息、商品详情) |
掌握这些 ArkTS 高级数据类型,能让你的代码从 “能用” 升级到 “好用”—— 更易读、更安全、更易维护。后续开发鸿蒙应用时,不妨多思考 “哪种数据类型最适合当前场景”,慢慢养成良好的编码习惯。下一篇我们将讲解 ArkTS 的运算符与表达,带你进一步提升鸿蒙开发能力。如果本文对你有帮助,欢迎点赞、收藏!若你想系统学习鸿蒙开发,深入掌握更多 ArkTS 核心技术,拿到基础、高级等开发者证书,欢迎加入我的鸿蒙班,一起从入门到精通: