鸿蒙开发必备:ArkTS 高级数据类型详解,从理论到实战

164 阅读9分钟

在鸿蒙应用开发中,ArkTS** 作为主力开发语言,其高级数据类型是构建复杂功能的基础。掌握数组、枚举、联合这几种核心高级类型,能让你的代码更简洁、可读性更强、扩展性更优。今天就带大家从实际场景出发,吃透这些关键知识点,助力你高效开发鸿蒙应用。

一、枚举类型:给 “魔法数字” 起个 “好名字”

1. 为什么需要枚举?

开发中你是否遇到过这样的问题:代码里充斥着012这类 “魔法数字”,比如用0代表 “播放”、1代表 “暂停”、2代表 “停止”。过段时间再看代码,根本记不清这些数字的含义;团队协作时,新人更是需要反复询问才能理解。

枚举(Enum)就是为解决这个问题而生 —— 它用有意义的名称替代固定值,约定变量只能在一组预设范围内取值,让代码 “自解释”。

比如淘宝 APP 的主题色控制:直接写颜色编码#ff0f29#ff7100不够直观,但用RedOrangeGreen来表示,任何人看代码都能瞬间明白对应的颜色含义。

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 个学生的姓名,用常规变量需要定义name1name2...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(如pushpopfind等)高效处理数据。

实战示例:

// 方式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 核心技术,拿到基础、高级等开发者证书,欢迎加入我的鸿蒙班,一起从入门到精通:

developer.huawei.com/consumer/cn…