Skip to content

ArkTS 数据结构

struct vs class 的深层理解、Sendable 对象机制、ArkTS 中的集合类型。


1. struct(结构体)在 ArkTS 中的角色

1.1 struct 的用途

在 ArkTS 中,struct 有两个核心用途:

  1. UI 组件定义(配合 @Component 装饰器)
  2. 纯数据容器(类似 DTO/POJO)

1.2 UI 组件 struct

typescript
@Component
struct UserInfo {
    @State name: string = '未知'
    @State age: number = 0
    @State avatar: Resource = $r('app.media.default_avatar')

    build() {
        Row() {
            Image(this.avatar)
                .width(48)
                .height(48)
                .borderRadius(24)
            Column() {
                Text(this.name)
                    .fontSize(16)
                    .fontWeight(FontWeight.Bold)
                Text(`${this.age}岁`)
                    .fontSize(14)
                    .fontColor(Color.Gray)
            }
            .margin({ left: 12 })
        }
        .width('100%')
        .padding(12)
    }
}

1.3 数据容器 struct

typescript
// 纯数据容器,不需要 @Component
struct Point {
    x: number
    y: number
}

struct Size {
    width: number
    height: number
}

struct Rect {
    top: number
    left: number
    width: number
    height: number
}

// 使用
const rect: Rect = { top: 0, left: 0, width: 100, height: 200 }

2. struct vs class 对比

维度structclass
用途UI 组件、数据容器逻辑类、业务逻辑
继承❌ 不可继承✅ 可继承
装饰器@Component(组件必选)无强制要求
必须实现build() 函数
实例化new MyStruct()new MyClass()
状态管理可用 @State/@Prop 等普通类属性
编译优化AOT 编译AOT 编译
内存开销更低(编译器优化)略高

决策流程图

需要创建 UI 组件?
├─ 是 → struct + @Component
└─ 否
   ├─ 需要继承? → class
   ├─ 需要状态管理? → struct
   └─ 其他 → class(更灵活)

3. Sendable 对象

3.1 什么是 Sendable?

Sendable 是 ArkTS 中用于线程间传递的特殊对象类型。它实现了 ISendable 接口,可以在 Actor 模型的线程间通过引用高效传递,而无需序列化。

typescript
interface ISendable {
    __isSendable__: true
    readonly id: string
}

// 实现 Sendable 接口的类
class Message implements ISendable {
    __isSendable__: true = true
    readonly id: string
    readonly content: string
    readonly timestamp: number

    constructor(content: string) {
        this.id = `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`
        this.content = content
        this.timestamp = Date.now()
    }
}

// 线程间传递(无需序列化)
async function sendMessage() {
    const msg = new Message('Hello')

    await TaskPool.execute(() => {
        // 子线程中直接访问
        console.log(msg.content)  // 高效传递
    })
}

3.2 Sendable 的规则

  1. 只能包含基本类型和 Sendable 字段
  2. 字段必须是 readonly(不可变)
  3. 不能包含非 Sendable 对象引用
  4. 不能包含闭包/函数引用

4. 集合类型

4.1 Array

typescript
// 创建数组
let arr: number[] = [1, 2, 3]
let arr2: Array<string> = ['a', 'b', 'c']

// 常用方法
arr.push(4)          // 追加
arr.pop()            // 弹出最后一个
arr.shift()          // 弹出第一个
arr.unshift(0)       // 头部追加
arr.splice(1, 1)     // 删除索引1的元素
arr.indexOf(2)       // 查找索引
arr.includes(2)      // 是否包含

// 迭代
arr.forEach((item, index) => {
    console.log(index, item)
})

// 映射
const doubled = arr.map(x => x * 2)

// 过滤
const evens = arr.filter(x => x % 2 === 0)

// 查找
const found = arr.find(x => x > 2)

// 排序
arr.sort((a, b) => a - b)  // 升序
arr.reverse()               // 反转

4.2 Map

typescript
// Map:键值对集合,键可以是任意类型
let userMap = new Map<string, User>()
userMap.set('user1', { id: 1, name: '小明' })
userMap.set('user2', { id: 2, name: '小红' })

console.log(userMap.get('user1'))     // 获取
console.log(userMap.has('user1'))     // 检查
console.log(userMap.size)             // 大小
userMap.delete('user1')               // 删除

// 遍历
for (const [key, value] of userMap) {
    console.log(key, value.name)
}

4.3 Set

typescript
// Set:唯一值集合
let tags = new Set<string>()
tags.add('鸿蒙')
tags.add('ArkTS')
tags.add('鸿蒙')  // 重复,不会添加

console.log(tags.has('鸿蒙'))   // true
console.log(tags.size)          // 2

// 遍历
for (const tag of tags) {
    console.log(tag)
}

5. ArkTS 中的对象类型

5.1 Object 与 Record

typescript
// 普通对象(类型较宽泛)
let obj: object = { name: '小明' }

// Record 对象(类型精确)
let dict: Record<string, number> = {
    'a': 1,
    'b': 2
}

// 对比性能:Record 的 Hidden Class 优化更好
type UserDict = Record<string, User>
const users: UserDict = {}

5.2 深拷贝 vs 浅拷贝

typescript
// 浅拷贝(推荐用展开运算符)
let original = { name: '小明', address: { city: '北京' } }
let shallow = { ...original }
shallow.address.city = '上海'
console.log(original.address.city)  // '上海'(浅拷贝!)

// 深拷贝(需要递归实现)
function deepClone<T>(obj: T): T {
    return JSON.parse(JSON.stringify(obj))
}

let deep = deepClone(original)
deep.address.city = '上海'
console.log(original.address.city)  // '北京'(深拷贝!)

💡 面试考点:ArkTS 中推荐使用深拷贝 + 赋值来修改数组/对象,避免直接引用修改导致的数据一致性问题。


6. 面试高频考点

Q1: struct 和 class 在 ArkTS 中的区别?

回答:UI 组件用 struct(不可继承,必须有 build());纯逻辑类用 class(可继承,更灵活)。struct 编译优化更好,class 支持继承和更完整的 OOP 特性。

Q2: Sendable 对象的作用?

回答:在 Actor 模型的线程间传递对象时,实现 Sendable 接口可避免序列化,通过引用高效传递。要求字段 readonly、只包含基本类型和 Sendable 字段。

Q3: ArkTS 中深拷贝的推荐方式?

回答:JSON.parse(JSON.stringify(obj)) 是最常用的深拷贝方式。在状态变更时应该用深拷贝+赋值,而非直接修改引用。


🐱 小猫提示:数据结构部分记住两个核心对比:struct vs class 的适用场景区分,以及深拷贝 vs 浅拷贝的使用场景。