仓颉语言开发指南

写给 Java 开发者的仓颉编程语言完整手册 —— 从基础语法到轻量线程,从模式匹配到空安全

仓颉 1.1.0 · HarmonyOS 6 / 跨平台 Java 21 LTS / 25+ ↔ 仓颉 19 个核心主题 50+ 代码示例

🎯01 · 设计哲学对比

仓颉是华为为鸿蒙原生生态自主研发的通用编程语言,融合了面向对象、函数式、命令式多范式,原生支持空安全、模式匹配、轻量线程与元编程。它不是"另一个 Java",而是吸收了 Kotlin / Rust / Go / Swift 精华后,为原生应用与云化场景重新设计的现代语言。

维度Java仓颉
语言范式纯 OOP(class 是一等公民)多范式:OOP + FP + 命令式
类型推断var(Java 10+,仅局部)全场景类型推断
空安全无(靠 @Nullable + 规范)Option 类型?T / Some / None),编译期杜绝 NPE
模式匹配switch + pattern matching(21+)原生 match 表达式:值/类型/解构匹配
异步CompletableFuture / Virtual Thread(21+)轻量线程spawn + Future
扩展机制继承 + 工具类 / 装饰者原生扩展extend Type { ... }
数据类record(16+)/ Sealed(17+)struct / class(值类型 / 引用类型)
字符串String + text block(15+)/ String templates(预览)字符串插值 "hello ${name}"
编译产物JVM 字节码 / native image仓颉 IR → 原生二进制(AOT)/ CJVM 字节码
泛型类型擦除(运行期)编译期特化(运行时保留类型信息)
命名参数原生支持name!: Type = 默认值
AI 智能体需第三方框架内嵌 AgentDSL(多 Agent 编排)
💡 仓颉与 Kotlin / Rust / Go / Swift 的关系

仓颉的很多特性借鉴了现代语言的成熟设计:空安全 + 扩展 + 模式匹配 → 类似 Kotlin / Swiftlet / var / match → 类似 SwiftResult<T,E> + 代数数据类型 → 类似 Rustspawn + 轻量线程 → 类似 Go。但它把这些融合为统一的语言体验,并为鸿蒙原生场景做了深度优化(AOT 编译、跨设备协同、端侧 AI)。如果你熟悉其中任一语言,很多概念会似曾相识。

⚠️ 关于版本与准确性的说明

仓颉仍在快速演进。本文档基于 仓颉 1.1.0(2026-04 发布,已支持 Android / iOS 跨平台运行,中心仓正式上线)。核心语法matchspawn?T / Optionextend<: 等)均依据官方文档编写;但具体 API 名称、标准库路径、Agent DSL 细节会随版本变化,请以 官方文档 为最终权威。文中标注"(示意)"处为传达概念而写的简化代码。

🛠️02 · 开发环境

Java 开发者熟悉的 Maven / Gradle 在仓颉中由 hvigor(构建)+ OHPM(包管理,OpenHarmony Package Manager)替代。IDE 使用 DevEco Studio(基于 IntelliJ 平台,操作习惯与 IDEA 接近)。

能力Java仓颉
构建工具Maven / Gradlehvigor
包管理Maven CentralOHPM 中心仓
IDEIntelliJ IDEA / EclipseDevEco Studio
编译器javaccjc
运行JVM原生二进制(CJNative)/ 仓颉 VM(CJVM)
单元测试JUnit内置测试框架
✅ 编译与运行

单个文件可用 cjc hello.cj -o hello 直接编译为原生二进制;工程内则通过 hvigor 任务构建。仓颉同时支持 CJNative(原生二进制)与 CJVM(字节码)两种后端。

👋03 · Hello World

☕ Java
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
🟣 仓颉
main(): Unit {
    println("Hello, World!")
}
✅ 与 Java 的关键差异
  • 没有类包裹:仓颉是"包级"程序,main() 是顶层函数,不需要 public class Main
  • 不需要 new:构造对象直接写 Foo(),没有 new 关键字。
  • func 关键字:定义函数用 func(不是 Java 的方法签名直接写)。
  • Unit 替代 voidUnit 是真实类型(唯一实例为 ()),函数体最后一项表达式即为返回值。
  • 分号可选:语句结尾的分号可写可不写(推荐省略)。
  • 包声明:用 package xxx 声明包,import std.io.* 导入标准库。

🔤04 · 变量与类型

变量声明

☕ Java
int x = 10;
final double PI = 3.14;
String name = "Alice";

// Java 10+ 类型推断
var list = new ArrayList<String>();

// 可空
String s = null;  // 没有编译保护
🟣 仓颉
let x: Int64 = 10
let PI = 3.14      // 推断:Float64
var name = "Alice"   // 可变变量

// let vs var
let y = 20  // 不可变(推荐,类似 final)
var z = 20  // 可变

// 空安全:用 Option 表达"可能没有值"
let s: String = "hi"        // 非空,不能赋空
let s: ?String = None  // 可空,?String = Option<String>
let s: Option<String> = Some("hi")
✅ 仓颉的 let vs var

let:不可变绑定(类似 Java final),推荐优先使用。var:可变变量。仓颉的类型推断很强,大多数情况不用写类型标注。

类型系统对比

概念Java仓颉
有符号整数byte/short/int/longInt8/Int16/Int32/Int64
无符号整数UInt8/UInt16/UInt32/UInt64
浮点float/doubleFloat16/Float32/Float64
布尔booleanBool
字符char(UTF-16)Rune(Unicode 码点)
字符串String(引用)String(值类型)
单元类型voidUnit(实例 ()
元组(String, Int64)
可空类型@Nullable T?T(即 Option<T>
顶层类型ObjectAny(所有类型隐式实现)
⚠️ 与 Java 不同的类型习惯
  • 没有 int 这种模糊类型:仓颉用定宽整数 Int64(对应 Java long)、Int32(对应 int)。Int64 是最常用的整数类型。
  • Rune 不是 Char:仓颉的字符类型是 Rune(一个 Unicode 码点),不是 Java 的 16 位 char
  • 没有 null 关键字:空值用 NoneOption 类型的一个构造器)表达。
  • 可空类型写在前缀:写成 ?String(不是 Kotlin/TS 的 String? 后缀)。

字符串插值

☕ Java · String.format
String name = "Alice";
int age = 18;
String s = String.format(
    "Name: %s, Age: %d", name, age);
🟣 仓颉 · 字符串插值
let name = "Alice"
let age = 18
let s = "Name: ${name}, Age: ${age}"
// 表达式嵌入
let msg = "Next year: ${age + 1}"

🔀05 · 控制流

仓颉的控制流继承现代语言惯例:if/else表达式(有返回值),用 match 替代 switch(更强大),for 循环支持范围表达式。注意:仓颉用 match(不是 Kotlin/Swift 的 when)。

if 表达式 —— 有返回值

☕ Java · if 语句
// 不能用 if 直接赋值
String label;
if (score >= 60) {
    label = "pass";
} else {
    label = "fail";
}
// 三元运算符
String label = score >= 60
    ? "pass" : "fail";
🟣 仓颉 · if 表达式
// if 是表达式,直接赋值!
let label =
    if (score >= 60) {
        "pass"
    } else {
        "fail"
    }
// 不需要三元运算符

match —— 进化版 switch

☕ Java · switch
switch (day) {
    case "sat":
    case "sun":
        msg = "weekend"; break;
    default:
        msg = "weekday";
}
// Java 14+ switch 表达式
var msg = switch (day) {
    case "sat", "sun" -> "weekend";
    default -> "weekday";
};

// Java 21+ pattern matching for switch(类型匹配)
static String describe(Object o) {
    return switch (o) {
        case Integer i -> "int " + i;
        case String s -> "str " + s;
        case null -> "null";
        default -> "other";
    };
}
🟣 仓颉 · match 表达式
let msg = match (day) {
    case "sat" | "sun" => "weekend"
    case _ => "weekday"
}

// 范围/条件匹配:用守卫 where
let grade = match (score) {
    case s where s >= 90 => "A"
    case s where s >= 80 => "B"
    case s where s >= 60 => "C"
    case _ => "D"
}
✅ match 比 switch 强大太多

Java 的 switch 从 21+ 才开始支持类型模式匹配case Integer i ->),但仍缺少守卫模式和穷尽性编译期检查;仓颉的 match 从一开始就支持:常量模式(case "sat" | "sun")、守卫模式case s where s >= 90)、类型模式case b: Base)、解构模式case (name, age))、enum 模式。而且 match表达式,可以直接赋值,且必须穷尽(漏分支编译报错)——这是 Java 21 也达不到的。

for 循环与范围表达式

☕ Java
// 经典 for
for (int i = 0; i < 10; i++) { }

// 增强 for
for (String s : list) { }

// while
while (cond) { }
🟣 仓颉
// 半开区间 [0, 10)
for (i in 0..<10) { }
// 闭区间 [1, 10]
for (i in 1..=10) { }

// 遍历集合
for (s in list) { }

while (cond) { }

🧩06 · 函数

仓颉用 func 定义函数,函数是一等公民(可赋值、传参、返回)。函数体最后一项表达式即为返回值,无需显式 return

☕ Java
// 必须写返回类型,void 不能省
int add(int a, int b) {
    return a + b;
}
// 无默认值 / 无命名参数
🟣 仓颉
// 最后一项表达式即返回值
func add(a: Int64, b: Int64): Int64 {
    a + b
}
// 多返回值:用元组
func divMod(a: Int64, b: Int64): (Int64, Int64) {
    (a / b, a % b)
}

命名参数与默认值

🟣 仓颉 · 命名参数(! 后缀)
// 命名参数名后加 !,调用时写 名字: 值,可设默认值
func createUser(name!: String, age!: Int64 = 18) {
    println("${name}, ${age}")
}
createUser(name: "Alice")            // age 用默认值 18
createUser(name: "Bob", age: 25)   // 可任意顺序
⚠️ 命名参数规则

非命名参数(a: T)必须在前,命名参数(name!: T)必须在后且不可交替;只有命名参数可以设默认值。调用时命名参数可打乱顺序。

Lambda 与函数类型

🟣 仓颉 · 一等公民函数
// 函数类型:(参数) -> 返回
let double: (Int64) -> Int64 = { x => x * 2 }
// 无参
let hi: () -> Unit = { => println("hi") }

// 高阶函数
func apply(a: Int64, b: Int64, op: (Int64, Int64) -> Int64): Int64 {
    op(a, b)
}
apply(3, 4, { x, y => x + y })  // 7
💡 与 Java 的差异

Java 用 Function<T,R> / 方法引用 / lambda;仓颉直接用 (T) -> R 函数类型,lambda 用 { x => ... }。注意仓颉没有方法重载,靠命名参数 + 默认值替代。

🏛️07 · 面向对象

仓颉支持 class(引用类型)、struct(值类型)、interfaceenum。单继承(类只能有一个父类),但可实现多个接口。默认所有类都隐式是 Object 的子类,且所有类型都隐式实现 Any

类与接口

☕ Java
interface Drawable {
    void draw();
}
open class Shape {
    public void draw() {}
}
class Circle extends Shape
    implements Drawable {
    @Override
    public void draw() {}
}
🟣 仓颉
interface Drawable {
    func draw(): Unit
}
open class Shape {
    public func draw(): Unit {}
}
// <: 表示继承/实现;& 连接多个接口
class Circle <: Shape & Drawable {
    public override func draw(): Unit {}
}
⚠️ 三个易错点
  • 继承用 <:,不是 :class Foo <: Base & IFoo。多个接口用 & 连接。
  • 默认 final:类默认不可被继承,必须用 open 修饰才能继承;成员函数默认不可重写,需用 open 修饰、子类用 override 重写。
  • 没有 new:构造直接写 Circle()

struct(值类型)与 class(引用类型)

🟣 仓颉 · struct 数据载体
struct Point {
    let x: Int64
    let y: Int64
    public init(x: Int64, y: Int64) {
        this.x = x
        this.y = y
    }
}
let p = Point(x: 3, y: 4)  // 值类型,复制传值

// class 是引用类型,多个变量共享同一实例
class Animal {
    var name: String
    public init(name: String) { this.name = name }
}
✅ Java 的 record / data class → 仓颉的 struct

仓颉没有 Java 的 record 关键字。承载数据的不可变对象用 struct(值类型,复制语义,适合 POJO / DTO);需要继承、多态、共享可变状态时用 class

静态成员

🟣 仓颉 · 顶层函数 + static
// 顶层函数(不在 class 内)等价于 Java 静态工具方法
func formatName(n: String): String { n }

class Counter {
    public static let max = 100      // 静态字段
    public static func reset(): Unit {}  // 静态方法
}

🛡️08 · 空安全

仓颉没有 null 关键字。引用类型永远非空;"可能没有值"用 Option 类型表达(Some(v) 表示有值,None 表示无值)。?TOption<T> 的语法糖。

☕ Java
String s = null;  // 编译通过
println(s.length());  // 运行时 NPE

if (s != null) {
    println(s.length());
}
🟣 仓颉
// 非空类型不能赋 None
let s: String = None      // ❌ 编译错误
let s: ?String = None    // ✅ 可空

// 可选链 ?. 与空合并 ??
let len = s?.length        // ?String 类型
let len = s ?? ""        // s 为 None 时用 "" 

// 用 match 解构(穷尽,编译器强制处理 None)
match (s) {
    case Some(v) => println(v.length)
    case None => println("no value")
}
💡 Option 的本质

Option<T> 是一个泛型枚举:enum Option<T> { | Some(T) | None }。因为 TOption<T> 是不同类型,你无法直接对可空值解引用——必须先 match 或用 ?. / ??,从而在编译期杜绝 NPE。上下文需要 Option 时,直接传 T 类型的值会被自动包装成 Some(...)

⚠️ 常见疑惑
  • 没有 !! 断言运算符:仓颉用 match / ?. / ?? 安全处理,而不是 Kotlin 的 !! 强制解包。
  • 可空写在前缀?String 不是 String?
  • 返回值可能为"无"时优先用 Option<T>:语义比布尔 + 副作用清晰,且编译器强制调用方处理。

🎯09 · 模式匹配

match 是仓颉最强大的控制结构。除了第 05 节的常量/守卫匹配,它还能解构 enum、元组,并做类型判断——彻底替代 Java 的 instanceof + 强制转型。

enum 与解构匹配

🟣 仓颉 · enum 模式
enum Shape {
    | Circle(Float64)        // 半径
    | Rect(Float64, Float64) // 宽、高
}
func area(s: Shape): Float64 {
    match (s) {
        case Circle(r) => 3.14 * r * r
        case Rect(w, h) => w * h
    }
}
✅ enum 语法要点

构造器用 | 分隔(如 | Circle(Float64) | Rect(...) );无参构造器如 | Red | Green | Blue。enum 是值类型的代数数据类型(和类型),非常适合状态机、返回码、协议字段。

类型模式替代 instanceof

☕ Java
if (obj instanceof Dog d) {
    d.bark();
} else if (obj instanceof Cat c) {
    c.meow();
}
🟣 仓颉
match (obj) {
    case d: Dog => d.bark()
    case c: Cat => c.meow()
    case _ => println("unknown")
}

元组与守卫组合

🟣 仓颉 · 嵌套模式
func classify(point: (Int64, Int64)): String {
    match (point) {
        case (0, 0) => "原点"
        case (x, 0) where x > 0 => "X 轴正半轴"
        case (x, y) => "(${x}, ${y})"
    }
}
💥 match 必须穷尽

仓颉的 match 要求覆盖所有可能分支(对 enum 要覆盖所有构造器),否则编译报错。若确实无法列举,必须加 case _ => 兜底。这比 Java 的 switch(漏 case 只是警告)安全得多。

🤖10 · 智能体(Agent)

仓颉的一大特色是内嵌 AgentDSL——把 LLM 多智能体编排作为一等公民融入语言,让自然语言与编程语言有机融合,支持多 Agent 协同。这是 Java 生态需要借助 Spring AI 等第三方框架才能实现的能力,在仓颉中是语言级原生支持

💡 与 Java 的根本区别

Java 做 AI Agent 要引入 LangChain4j / Spring AI 等库,用注解 + 配置 + 运行时编排;仓颉把 Agent 定义、工具调用、多 Agent 协作通过 声明式 DSL 直接写进代码,编译期校验、运行期高效。这更像是"为 AI 原生应用设计的语言"——正如 HarmonyOS 面向端侧 AI 的场景定位。

⚠️ 写法以官方 SDK 为准

AgentDSL 的具体语法(Agent 定义、工具声明、多 Agent 通信原语)会随版本演进,且属于较新的特性。本文不展示具体代码以免失真——建议以 官方 Agent 开发文档 中的示例为准。作为 Java 开发者,你只需理解:仓颉把"构建多智能体应用"当成语言内建能力,而非外部框架

✅ 迁移视角

如果你在 Java 中用 @Agent / @Tool 注解做 AI 编排,在仓颉中会收敛为统一的 Agent DSL;如果还没用过 AI Agent 框架,可以从仓颉的官方示例起步,它的端侧 AI 场景(手机 App 内本地推理 + 多 Agent)是最直接的落地场景。

11 · 属性与扩展

计算属性(property)

🟣 仓颉 · 计算属性
struct Circle {
    let r: Float64
    public init(r: Float64) { this.r = r }
    // 计算属性:像字段一样访问,背后是 get
    public property area: Float64 {
        get { 3.14 * r * r }
    }
}
let c = Circle(r: 2.0)
println(c.area)   // 像字段访问,实际调用 get
✅ 对比 Java

Java 用 getArea() / Lombok @Getter;仓颉用 property area { get { ... } },调用时像字段一样写 c.area,比 Java 的 getter 方法更简洁。

扩展(extend)

☕ Java · 工具类
class StringUtil {
    static boolean isInt(String s) {
        try {
            Integer.parseInt(s);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
StringUtil.isInt("123");
🟣 仓颉 · 扩展函数
// 给已有类型"追加"方法,无需改源码
extend String {
    public func isInt(): Bool {
        match (toInt64()) {
            case Some(_) => true
            case None => false
        }
    }
}
"123".isInt()  // true,像原生方法一样调用
✅ 扩展的优势

扩展函数在编译期静态展开(无反射、无运行时开销),可以扩展标准库、第三方库甚至你无法修改的类。语法是 extend Type { func ... }不是 Kotlin 的 fun Type.xxx()

⚠️ 扩展函数没有多态

扩展函数是静态分发的:调用哪个版本在编译期由静态类型决定,不随运行时实际类型变化。这与 Java 的实例方法(动态派遣)不同——不要把扩展当作"子类重写"。

📚12 · 集合与泛型库

仓颉标准库提供 Array(定长数组)、ArrayList(动态数组)、HashSetHashMap 等集合类型。结合扩展函数与 lambda,可以用函数式风格处理集合。

Java仓颉
List<String> / ArrayListArrayList<String>
Set<T> / HashSetHashSet<T>
Map<K,V> / HashMapHashMap<K,V>
String[]Array<String>
Stream API(filter/map集合扩展 + lambda(filter/map 等)
☕ Java · Stream
var res = list.stream()
    .filter(s -> s.length() > 3)
    .map(String::toUpperCase)
    .toList();
🟣 仓颉
let res = list
    .filter { s => s.size > 3 }
    .map { s => s.toUpperCase() }
⚠️ 没有内建 Set 字面量

仓颉没有 Java Set.of(...) 那样的集合字面量语法糖;集合用构造函数创建(如 HashSet<Int64>()put)。需要"集合去重"语义时,用 HashSet 或过滤后转 ArrayList

13 · 轻量线程与异步

仓颉的并发模型核心是用户态轻量线程(官方称"轻量化线程")。用 spawn 创建轻量线程,返回一个 Future<T>;通过 Future.get() 等待结果。这与 Java 的 CompletableFuture 思路相近,但语法是 spawn 而非 async/await

☕ Java · CompletableFuture
CompletableFuture<String> f =
    CompletableFuture.supplyAsync(() -> {
        return fetch(url);
    });
String r = f.get();  // 阻塞等待
🟣 仓颉 · spawn + Future
import std.sync.*

func fetchData(url: String): Future<String> {
    spawn {
        return httpGet(url)  // 返回值即 Future 的结果
    }
}
main(): Unit {
    let fut = fetchData("https://x.com")
    let r = fut.get()   // 阻塞等待结果
    println(r)
}
✅ spawn 的关键事实
  • spawn { ... } 创建用户态轻量线程,开销远小于 OS 线程,可轻松创建成千上万个。
  • 闭包最后一项表达式即 Future<T> 的结果;fut.get() 阻塞直到完成。
  • fut.tryGet() 返回 Option<T>——有结果时 Some(v),未完成时 None(非阻塞)。
  • 每个 Future 对应一个 Thread 对象,可通过 Thread.currentThreadfut.thread.id 访问线程信息。
⚠️ 没有 async / await

仓颉不使用 Kotlin/JS 的 async/await 关键字。异步逻辑通过 spawn + Future.get()(或 tryGet())表达。主线程不会自动等待轻量线程结束,需要显式 get()join

💡 对比 Java 21 虚拟线程

Java 21 的 Virtual Thread 是JVM 托管的轻量 OS 线程,仍是共享内存 + 锁模型;仓颉轻量线程是用户态调度的协作式任务。写法上:

  • Java 21:Thread.startVirtualThread(() -> ...)Executors.newVirtualThreadPerTaskExecutor()
  • Java 21+ Structured Concurrency:StructuredTaskScope 管理线程作用域与取消
  • 仓颉:spawn { ... } + Future.get()

两者都让高并发更简单,但仓颉从语言层内置、无历史包袱,而 Java 是逐步演进到 21 才补齐虚拟线程与结构化并发。

🚨14 · 错误处理

仓颉提供两套错误处理机制:传统的 try-catch-finally 异常机制,以及函数式的 Result<T, E> + match(把错误当值处理)。Java 开发者对前者很熟悉。

try-catch(异常机制)

☕ Java
try {
    int x = 10 / 0;
} catch (ArithmeticException e) {
    log(e);
} finally {
    cleanup();
}
🟣 仓颉
try {
    let x = 10 / 0
} catch (e: ArithmeticException) {
    println(e)
} finally {
    cleanup()
}

Result 类型(函数式)

🟣 仓颉 · Result<T, E> + match
// Result 是枚举:Success(T) 或 Error(E)
func readFile(path: String): Result<String, IOException> {
    // 成功:Success(content);失败:Error(e)
}
match (readFile("a.txt")) {
    case Success(content) => println(content)
    case Error(e) => println("err: ${e}")
}
✅ 两种风格怎么选

需要"异常穿透调用栈"时用 try-catch(和 Java 一致);希望编译期强制调用方处理失败时用 Result<T,E> + match(类似 Rust,不可能漏处理错误分支)。

⚠️ 不要用 match 硬套异常

异常(throw)走 try-catchResult 是普通返回值,走 match。两者是不同机制,不要把抛出的异常当成 Resultmatch

🧬15 · 泛型

仓颉泛型的重大差异:编译期特化(monomorphization),而非 Java 的类型擦除。泛型函数在编译期为每个具体类型生成独立代码,运行时保留类型信息,没有 Java 的 List<String>.class 擦除陷阱。

☕ Java · 类型擦除
class Box<T> {
    private T value;
    public T get() { return value; }
}
// 运行时 Box<String> 与 Box<Integer>
// 是同一个 Class(擦除为 Box)
🟣 仓颉 · 编译期特化
class Box<T> {
    var value: T
    public init(v: T) { value = v }
    public func get(): T { value }
}
// 编译期为 Box<String>、Box<Int64>
// 各自生成真实类型代码
✅ 实用优势

因为运行时保留类型信息,仓颉泛型可以做值类型特化Box<Int64> 不含对象头开销),性能更好;也不会遇到 Java 泛型数组、instanceof 擦除等限制。

🔧16 · 操作符重载

仓颉允许为自定义类型重载操作符,用 operator func 前缀。语法是操作符符号本身(如 +==),不是 Kotlin 的 plus / equals 命名。

🟣 仓颉 · operator func
struct Point {
    let x: Int64
    let y: Int64
    public init(x: Int64, y: Int64) {
        this.x = x; this.y = y
    }
    public operator func +(rhs: Point): Point {
        Point(x: x + rhs.x, y: y + rhs.y)
    }
    public operator func ==(rhs: Point): Bool {
        x == rhs.x && y == rhs.y
    }
}
let p = Point(1, 2) + Point(3, 4)  // Point(4, 6)
操作符仓颉声明使用
+operator func +(rhs)a + b
-operator func -(rhs)a - b
*operator func *(rhs)a * b
==operator func ==(rhs)a == b
[]operator func [](i)a[i]
..operator func ..(rhs)a..b
⚠️ 与 Java 的差异

Java 不支持自定义操作符重载(只能重写 equals);仓颉用 operator func +(...) 直接重载符号。注意具体可重载的操作符集合以官方文档为准。

🧵17 · 并发模型

仓颉的并发是用户态轻量线程 + Channel 通信(CSP 模型)。单看线程模型类似 Go 的 goroutine,但仓颉同时支持多线程内存共享(高性能场景),并用 atomic 原语保证共享安全。

维度Java仓颉
线程模型OS 线程 / 虚拟线程用户态轻量线程(spawn)
结果获取Future.get()Future.get() / tryGet()
线程间通信阻塞队列 / 共享内存 + 锁Channel(std.sync)/ 共享内存 + atomic
内存模型共享内存 + synchronized默认不共享,必要时用 atomic 原语
取消Future.cancel()Thread 取消信号(hasPendingCancellation)
🟣 仓颉 · spawn 多个轻量线程(示意)
import std.sync.*
import std.collection.*

func fetch(url: String): Future<String> {
    spawn { return httpGet(url) }
}
main(): Unit {
    let futs = ArrayList<Future<String>>()
    for (url in urls) {
        futs.append(fetch(url))
    }
    for (f in futs) {
        println(f.get())  // 等待每个线程完成
    }
}
💡 线程取消(示意 API)

轻量线程可通过父线程发送取消信号终止;在子线程中通过 Thread.currentThread.hasPendingCancellation 检查是否有待处理的取消请求,及时退出。具体取消原语以官方 SDK 为准。

💥 主线程不等待子线程

与 Java 一样,主线程结束进程就退出,不会自动等子线程。需要结果就必须显式 get()join;否则子线程可能还没跑完程序就结束了。

💣18 · 常见陷阱

💥 12 条 Java 开发者易踩的坑
  1. 模式匹配用 match 不是 when:仓颉是 match (x) { case ... => ... },别套 Kotlin/Swift 的 when
  2. 继承写 <: 不是 :class Foo <: Base & IFoo
  3. 默认 final:类/方法默认不可继承/重写,需 open / override
  4. 没有 new:构造直接写 Foo()
  5. 没有 null:用 Option / ?T / Some / None;可空写前缀 ?String 不是后缀。
  6. == 比较值不是引用:值类型直接比内容;类需重载 operator ==
  7. 字符类型是 Rune 不是 Char
  8. 整数是 Int64 不是 int:注意定宽类型。
  9. 没有 async / await:异步用 spawn + Future.get()
  10. match 必须穷尽:漏分支编译报错,记得 case _ => 兜底。
  11. 扩展函数静态分发:不随运行时类型多态,别当重写用。
  12. 没有 record 关键字:数据载体用 struct,可变对象用 class

🚀19 · 迁移建议与速查表

Java → 仓颉 概念映射

Java仓颉
public static void main顶层 main(): Unit
final 局部变量let
var / 普通变量var
record / Lombok @Datastruct
sealed class/interface(17+)match 穷尽 + enum / 封闭继承
class(引用)class / struct(值)
extends / implements<:(多接口用 &
@Overrideoverride
switch expression(14+)/ pattern matching(21+)match(原生穷尽 + 守卫)
instanceof + 转型match (x) { case t: T => ... }
@Nullable T / null?T / Option<T>
text block(15+)字符串插值 "hello ${name}" + 多行
StringUtils.xxx()extend String { func xxx() }
CompletableFuture / Virtual Thread(21+)spawn + Future
Structured Concurrency(21+)spawn + Future 编排
try-catch / 异常try-catchResult<T,E>
Stream.filter/map集合扩展 + lambda
synchronizedatomic 原语 / Channel
BlockingQueueChannel(std.sync)
Maven / Gradlehvigor + OHPM

快速上手检查清单

检查项要点
变量声明let(不可变)/ var(可变),信任类型推断
空安全思维可能没有值用 ?T / Option<T>,用 ?. / ?? / match 处理
if/match 是表达式直接赋值 let x = if (...) ... else ...,不再用三元
模式匹配替代 instanceofmatch (obj) { case t: T => ... }
继承写法class Foo <: Base & IFoo,需要继承/重写加 open / override
没有 new构造写 Foo()
类型名整数用 Int64,字符用 Rune
异步spawn { ... } + Future.get(),没有 async/await
match 穷尽覆盖所有分支,加 case _ => 兜底
集合与扩展ArrayList/HashSet/HashMap + extend 扩展
✅ 最终忠告

学习仓颉最大的障碍不是语法,而是放弃 Java 的防御性编码习惯:你不用再写 if (x != null)(编译器替你做了),不用再建 XxxUtils 工具类(扩展函数更自然),不用再写 CompletableFuture 链式回调(spawn + Future 更直接)。仓颉让编译器替你解决 Java 中最痛苦的部分——接受它,代码会短 30%~50%。