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 响应式刷新。

相关推荐
ldsweet1 天前
《HarmonyOS技术精讲-Basic Services Kit》线程通信利器:Emitter实现高效线程间消息传递
华为·harmonyos
心中有国也有家1 天前
AtomGit Flutter 鸿蒙客户端:Canvas 绘制进阶-路径、渐变与混合模式
android·javascript·flutter·华为·harmonyos
w139548564221 天前
鸿蒙应用开发实战【93】— 实战短信批量导入完整流程
华为·harmonyos·鸿蒙系统
Georgewu1 天前
【HarmonyOS 三方库 】Python 三方库鸿蒙化适配 PC 完整迁移实战
harmonyos
花开彼岸天~1 天前
鸿蒙应用开发实战【94】— 实战多卡号场景管理最佳实践
android·华为·harmonyos·鸿蒙系统
花开彼岸天~1 天前
鸿蒙应用开发实战【97】— 应用发布AGC上架全流程
华为·harmonyos·鸿蒙系统
绝世番茄1 天前
HarmonyOS Next 深入解析:Scroll 组件与 onScroll 滚动监听实战
华为·harmonyos·鸿蒙
2501_919749031 天前
华为鸿蒙免费铃声APP—小羊免费铃声
华为·harmonyos
不羁的木木1 天前
《HarmonyOS技术精讲-NearLink Kit(星闪服务)》第3篇:数据收发——点对点数据传输实战
pytorch·华为·harmonyos
木木子221 天前
[特殊字符] 种菜模拟器 — 鸿蒙ArkTS完整技术解析
microsoft·华为·harmonyos