HarmonyOS ArkTS 泛型:MyStack<T>、Pair<A,B> 与泛型函数

适用版本 :HarmonyOS 6.1(API 12)及以上

验证环境 :Pura 90 Pro 模拟器(HarmonyOS 6.1.1,API 24)

关键概念:泛型类、泛型函数、类型参数约束、不可变数组操作


前言

泛型是让一套逻辑适配多种类型的机制。ArkTS 支持 TypeScript 风格的泛型语法,但有几处严格模式限制需要注意------本文用三个典型例子覆盖完整用法:泛型类(栈结构)、泛型对(Pair)、泛型函数(findMax / reverseArray)。


一、泛型类:MyStack<T>

为什么不叫 Stack<T>?

ArkTS 内置了 Stack 类,直接命名会导致符号冲突。实际项目中自定义容器类应避免与内置类重名。

typescript 复制代码
class MyStack<T> {
  private items: T[] = []

  push(item: T): void {
    // ArkTS 严格模式禁止 spread:不能 [...this.items, item]
    // 必须手动循环重建数组
    const next: T[] = []
    for (let i = 0; i < this.items.length; i++) {
      next.push(this.items[i])
    }
    next.push(item)
    this.items = next
  }

  pop(): T | null {
    if (this.items.length === 0) { return null }
    const next: T[] = []
    for (let i = 0; i < this.items.length - 1; i++) {
      next.push(this.items[i])
    }
    const top = this.items[this.items.length - 1]
    this.items = next
    return top
  }

  peek(): T | null {
    if (this.items.length === 0) { return null }
    return this.items[this.items.length - 1]
  }

  isEmpty(): boolean { return this.items.length === 0 }
  size(): number { return this.items.length }

  toArray(): T[] {
    const copy: T[] = []
    for (let i = 0; i < this.items.length; i++) {
      copy.push(this.items[i])
    }
    return copy
  }
}

ArkTS 严格模式关键限制 :不支持扩展运算符 ... 操作数组(arkts-no-spread)。pushpop 都必须手动循环重建,这同时也满足不可变数据原则------每次操作返回新数组,不修改原数组。


二、泛型对:Pair<A, B>

封装两种不同类型的值,支持类型安全的 swap()

typescript 复制代码
class Pair<A, B> {
  first: A
  second: B

  constructor(first: A, second: B) {
    this.first = first
    this.second = second
  }

  // swap 返回新 Pair,类型参数交换
  swap(): Pair<B, A> {
    return new Pair<B, A>(this.second, this.first)
  }

  toString(): string {
    return `(${this.first}, ${this.second})`
  }
}

// 使用
const p = new Pair<string, number>('ArkTS', 12)
console.log(p.toString())      // (ArkTS, 12)
console.log(p.swap().toString()) // (12, ArkTS)

swap() 的返回类型 Pair<B, A> 利用泛型参数交换实现了编译期类型安全------交换后的 firstB 类型,secondA 类型,无需任何运行时类型检查。


三、泛型函数:findMax 与 reverseArray

ArkTS 严格模式不支持 extends 泛型约束(T extends Comparable),泛型函数的类型参数通常用于容器操作或委托比较:

typescript 复制代码
// 数字数组最大值(直接用 number,避免 extends 约束限制)
function findMax(arr: number[]): number | null {
  if (arr.length === 0) { return null }
  let maxVal = arr[0]
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] > maxVal) { maxVal = arr[i] }
  }
  return maxVal
}

// 反转任意类型数组(T 不需要比较能力,只需能存储)
function reverseArray<T>(arr: T[]): T[] {
  const result: T[] = []
  for (let i = arr.length - 1; i >= 0; i--) {
    result.push(arr[i])
  }
  return result
}

// 使用
const nums: number[] = [42, 7, 98, 15, 63, 31]
findMax(nums)           // 98
reverseArray(nums)      // [31, 63, 15, 98, 7, 42]
reverseArray(['a', 'b', 'c'])  // ['c', 'b', 'a']

reverseArray<T> 对任意类型数组都能复用同一逻辑,这是泛型的核心价值------一次编写,多类型复用


@State 与泛型类的配合

泛型类实例作为 @State 的问题:@State 只能追踪值类型(基础类型、class 实例)的变化,无法追踪内部属性变更 。解决方案是将快照同步为 @State 数组:

typescript 复制代码
// 私有持久化实例(不是 @State)
private numStack: MyStack<number> = new MyStack<number>()

// @State 快照,驱动 UI 刷新
@State stackSnapshot: number[] = []

// 每次 push/pop 后同步快照
private syncSnapshot(): void {
  const arr = this.numStack.toArray()
  const next: number[] = []
  for (let i = 0; i < arr.length; i++) { next.push(arr[i]) }
  this.stackSnapshot = next  // 赋值触发 @State 刷新
}

这种"持久化实例 + @State 快照"模式是处理复杂数据结构与 UI 响应式绑定的标准方式。


模拟器运行截图

初始状态

栈为空,三个操作区(MyStack、Pair、泛型函数)均处于等待状态。


执行完成

push(1)、push(2),peek() 确认栈顶为 2;Pair<string,number> 构造与 swap();findMax 和 reverseArray 均返回正确结果。

实测结果:

操作 输入 结果
push(1), push(2) MyStack 栈大小 2,peek() = 2
Pair<string,number> ('ArkTS', 12) (ArkTS, 12),swap() → (12, ArkTS)
findMax 42, 7, 98, 15, 63, 31 98
reverseArray 同上 31, 63, 15, 98, 7, 42

常见问题

Q:ArkTS 支持 T extends SomeInterface 这样的约束吗?

A:ArkTS 严格模式对泛型约束支持有限。T extends object 可以工作,但 T extends { compareTo(other: T): number } 这类结构化约束可能遇到编译错误。推荐改用函数参数传入比较器:function sort<T>(arr: T[], compare: (a: T, b: T) => number): T[]

Q:泛型类可以加 @Sendable 吗?

A:不能直接对泛型类加 @Sendable@Sendable 要求所有属性类型都是 Sendable 类型(number/string/boolean 或 collections.Array),而泛型 T 无法在编译期保证是 Sendable 类型。

Q:MyStack<T>push 为何不直接 this.items.push(item)

A:直接修改 this.items(可变操作)在 ArkTS 严格模式下通常没有编译错误,但 @State 不会感知到数组内部元素的增加------@State 追踪的是引用变化,不是内容变化。每次重建新数组并赋值,才能保证 UI 响应式刷新。

相关推荐
Magic-ZYJ10 小时前
HarmonyOS Release 构建安全:ArkGuard 混淆、签名配置与秘密管理
安全·华为·harmonyos·移动应用开发·心晴手记
见山是山-见水是水11 小时前
拆解HarmonyOS网络请求适配:原生鸿蒙页面的实现路径与调试方法
华为·harmonyos
m0_7496902311 小时前
【寻迹校园 HarmonyOS NEXT 实战 36】深色模式不是反色:用语义 Token 管理品牌色与状态色
harmonyos·arkts·深色模式·ui设计·主题设计
lqj_本人12 小时前
鸿蒙跨端实战_QT后台切换导致OpenGLES上下文丢失:黑屏自救指南
qt·华为·harmonyos
OH_TPC14 小时前
HarmonyOS APP开发---“数据眼“健康追踪App,需要用到这个库
华为·harmonyos·鸿蒙
lilian23314 小时前
Harmony os 技术实战|拼豆制图49:五组分类视觉规则如何收口成一张配置表
华为·harmonyos
2501_9197490315 小时前
华为鸿蒙免费决策APP—小羊挠头
华为·harmonyos·鸿蒙
m0_7496902315 小时前
【寻迹校园 HarmonyOS NEXT 实战 37】一套 ArkUI 适配四档宽度:sm、md、lg、xl 响应式 Shell 实战
华为·harmonyos·arkui·navigation·响应式布局·多设备适配
RisunJan17 小时前
HarmonyOS 架构精读:从系统分层到应用模型
华为·架构·harmonyos
见山是山-见水是水17 小时前
从需求到页面:鸿蒙原生 Ability 与 ArkTS 交互的 ArkTS 原生实现
华为·harmonyos