(特别说明:这篇笔记是我 2024 年华为仓颉发布后,基于官网公开信息梳理的个人学习笔记 —— 文中技术介绍、功能解读等核心内容均源自官网,仅做了结构优化和重点提炼。原本用于个人回顾,今天看到社区活动便整理分享出来,方便大家参考。需要提醒的是,由于技术迭代,当前仓颉语言的功能、特性可能已与文中内容存在差异,建议结合官网最新信息对照参考。若有疏漏,欢迎指正!)

简介


在这里插入图片描述
2024年6月21日,在华为开发者大会2024(HDC.2024)大会开始前夕,华为自研的“仓颉”编程语言正式亮相,相关官网也正式上线。自研一门编程语言是一项复杂的系统性工程,需要长期投入大量的人力、物力、财力,但是通过自主研发编程语言,华为可以掌握技术演进策略和方向,摆脱对外部技术的依赖。华为从 2019 年启动仓颉语言的开发计划,历经五年的专心打磨,在博采众家之长后,打造出了这门编程语言。仓颉编程语言是一款“面相全场景智能的新一代编程语言”,主打“原生智能化”、“天生全场景”、“高性能”和“强安全”,融入鸿蒙生态,为开发者提供良好的开发编程体验。
在这里插入图片描述

仓颉这个名字大家应该很熟悉了,应该都听过仓颉造字,据说仓颉“龙颜四目,生有睿德”,相传为黄帝的左史官,仓颉看见鸟兽的足迹受启发,加以搜集、整理和使用,在汉字创造的过程中起了重要作用,他将民间既有的图画文字进行广泛搜集,并加以认真整理,从而创制出一套成体系的规范的象形文字。可想而知,华为将自主编程语言命名为仓颉,是有很深的寓意在里面。接下来介绍一下仓颉的特性。

四大特性


在这里插入图片描述
华为官网的《仓颉编程语言白皮书》详细介绍了仓颉语言的几大特性。主要分为以下几点,高效编程、安全可靠、轻松并发、卓越性能;那为什么说自己的语言有这些特性呢,主要是因为仓颉降低了入门的门槛、支持多范式编程语言并且支持类型推断;在安全可靠方面仓颉的目标是编码即安全,仓颉编程语言是静态强类型语言,通过编译时类型检查尽早识别程序错误,降低运行时风险,也便于代码维护。仓颉程序中所有变量和表达式的类型都是在编译期确定的,并且在程序运行过程中不会发生改变。相比动态类型系统,静态类型系统对开发者有更多的约束,但能够在编译期尽量早的发现程序中的错误,提高程序的安全性,同时也让程序的行为更加容易预测,为编译优化提供了更多信息,使能更多的编译优化,提升程序的性能。同时,仓颉编译器提供了强大的类型推断能力,可以减少类型标注工作,提高开发效率。在内存安全方面:仓颉编程语言支持自动内存管理,并在运行时进行数组下标越界检查、溢出检查等,确保运行时内存安全。在并发方面仓颉编程语言提供了用户态轻量化线程(原生协程),以及简单易用的并发编程机制,保证并发场景的高效开发和运行。并且仓颉提供了基于细颗粒度并发算法实现的并发对象;仓颉在性能方面使用静态编译手段,将仓颉程序、核心库代码等编译成机器代码,加速程序运行速度。

高效编程

在高效编程方面,仓颉是一个典型的多范式编程语言,对过程式编程、面向对象编程和函数式编程都提供了良好的支持,包括值类型、类和接口、泛型、代数数据类型和模式匹配;仓颉在白皮书中提供了一些现代特性,比如对参数进行命名,命名参数是指在调用函数时,提供实参表达式的同时,还需要同时提供对应形参的名字。使用命名参数可以提升程序的可读性,减少参数的顺序依赖性,让程序更加易于扩展和维护。在仓颉中,函数定义时通过在形参名后添加 ! 来定义命名参数。当形参被定义为命名参数后,调用这个函数时就必须在实参值前指定参数名;
在这里插入图片描述
仓颉还提供了参数默认值,函数定义中,可以为特定形参提供默认值。函数调用时,如果选择使用该默认值做实参,则可以省略该参数。这个特性可以减少很多函数重载或者引入建造者模式的需求,降低代码复杂度。
在这里插入图片描述
仓颉中引入管道(Pipeline)操作符,来简化嵌套函数调用的语法,更直观的表达数据流向。在上面的例子中,给出了嵌套函数调用和与之等效的基于管道操作符|>的表达式。后者更加直观的反映了数据的流向:|>左侧的表达式的值被作为参数传递给右侧的函数。这里先对 5 执行double操作然后再double变成20 ,然后再加一再double,最后就是42,这样能很好表达数据的流向。
在这里插入图片描述
仓颉中定义了一系列使用特殊符号表示的操作符,其中大多数操作符都允许被重载,从而可以作用在开发者自己定义的类型上,为自定义类型的操作提供更加简洁直观的语法表达。在仓颉中只需要定义操作符重载函数就能实现操作符重载。在上面的例子中,我们首先定义一个类型Point表示二维平面中的点,然后我们通过重载+操作符,来定义两个点上的加法操作。
在这里插入图片描述

轻松并发

在这里插入图片描述
用户在并发场景调用原子类型和并发数据结构接口操作多线程共享对象不会产生“数据竞争”。原子类型为用户提供了并发场景下:整型、布尔型和引用类型的原子操作。并发数据结构的核心方法具有并发原子性,例如:ConcurrentHashMap 中的插入键值对 put,删除键值对 remove 和替换键值对 replace 等方法。并发场景下,用户可以将这些操作的调用执行视为原子的,不会被其它线程打断。仓颉的轻量化线程模型在性能上具有明显优势。由于其实现完全在用户空间进行,不依赖操作系统的线程管理,这从根本上减少了线程创建和销毁的开销,同时简化了线程调度流程。仓颉语言通过这种设计,实现了更高效的资源利用和更快的执行速度,尤其是在高并发场景下,这种优势更为显著。在一台常见的 x86 服务器上,仓颉线程创建的平均耗时远小于操作系统线程的创建开销。此外,一个仓颉线程仅占用 8Kb 内存资源,因此开发者可以在一个程序中同时创建十万级数量的仓颉线程,大大超出操作系统线程的限制。

卓越性能

仓颉语言通过值类型,这里的值类型与纯引用的编程语言像java、JavaScript等不同,并不只是对基础数据类型的支持,还包括其他数据类型比如数组,值类型的数组在访问上有更优秀的时间局部性,能够在运算、访问等操作带来更大的优势、除此之外仓颉还通过多层级静态分析优化和超轻量运行时,在计算机语言基准测试Benchmarks Game上,相比业界同类语言取得了较为明显的性能优势。至于为什么跟java、go、swift对比,是因为仓颉的定位就是重业务开发的静态类型语言。
在这里插入图片描述

在这里插入图片描述
在Java中,当需要执行垃圾回收时,垃圾回收器会停止应用程序的所有线程,以便安全地识别和回收不再使用的对象。这个过程被称为“STW”。STW事件会暂时中断应用程序的运行。对于需要高响应性或实时性能的应用程序,这可能引发性能问题,因为它会导致响应延迟。在STW期间,应用程序的响应时间(RT)和吞吐量(QPS)都会受到影响,这可能导致性能表现的不确定性,特别是在负载较高的情况下。为了减少STW带来的影响,需要对垃圾收集器的配置进行优化,例如选择不同类型的垃圾收集器、调整堆大小或其他垃圾收集器参数。例如,选择并发回收器作为垃圾回收器,如CMS、G1等,因为并发回收器主要关注的是减少STW的时长。它允许垃圾收集线程在应用程序线程运行的同时执行部分垃圾收集工作,从而减少了STW的时间。在并发回收期间,只会在特定的收集阶段发生短暂的STW。仓颉提供全并发的内存标记整理GC算法作为其自动内存管理技术的底座,具有延迟极低、内存碎片率极低、内存利用率高的优势。在官网中提到了实现高效的GC同步主要基于以下两点:安全点以及内存屏障,“安全点”机制包括两个组成部分:一是由编译器在编译仓颉代码时插入的安全点检查代码,一般插在必经路径上,比如函数头或尾,循环回边等处;二是GC算法中实现的安全点同步逻辑。当GC线程需要把GC状态同步到特定应用线程时,GC线程先激活该应用线程的安全点检查,后续当该应用线程执行到安全点检查代码时,看到自身的安全点处于激活状态,就会响应GC的同步请求,改变自身的GC状态至指定状态。通过安全点机制,GC现成可以控制应用线程的GC状态变更,配合内存屏障,让并发GC得以正确执行。不同的GC状态需要相应的内存屏障配合。“内存屏障”机制用于解决GC线程与仓颉线程的数据竞争。在并发GC中,最广泛存在的数据竞争是GC线程与应用线程的竞争。比如当GC线程想要把某个活对象移动到新地址,而几乎同时业务线程想要访问这个对象。内存屏障用于在应用线程访问内存时,可以跟GC线程采取协调一致的操作。除此之外,仓颉通过采用基于指针跳动技术的对象分配方式,大大提高了内存分配的速度,并且通过优化GC的开销,显著减少GC的持续时间。 接下来介绍一下仓颉的基础语法

基础语法

Hello,world

在这里插入图片描述
先用一个经典的Helloworld示例,来引入仓颉的基本语法,仓颉程序是写在扩展名为cj的文本文件中,这里创建了一个hello.cj的文本文件,然后里面写了注释以及main方法,并且打印了你好,仓颉;通过cjc 命令 指定源文件名,-o指定编译输出的可执行文件名,编译输出一个名为hello的ELF格式文件,在执行就能输出你好,仓颉。

标识符

接下来看一下标识符,仓颉的标识符命名规则图片中所示的两种,标识符由英文字母开头后接零至多个英文字母、数字或者下划线。由一至多个下划线开头后接英文字母,最后可接零至多个英文字母数字或者下划线,然后如果涉及将关键字作为标识符的场景,可以在关键字外面加上一对反引号。
在这里插入图片描述

变量

在仓颉中,变量分为可变变量、不可变变量、常量;不可变变量赋值后值不可变,并且值是在运行时求值,常量是在编译时求值,如果初始值具有明确的类型,可以省略变量类型标注,编译器会自动推断出变量类型;
在这里插入图片描述

案例

官网给了一个案例是通过蒙特卡洛方法利用概率统计来计算圆周率的近似值,有一个正方形,正方形中有一个内接圆,通过向正方形随机投点,然后统计落入正方形内接圆中的点数,利用内接圆的面积与正方形的面积相比,落入圆内的概率为四分之Π,然后通过计算每一个点到圆心的距离,统计出圆内的点数与总的随机点数相比,可以计算出Π的近似值。首先这里定义了一个常量N,标识总的投点数,一共10万个,小n代表落入圆内的点,然后通过for循环以及随机数随机点的xy坐标,再根据坐标到圆心的距离判断是否在圆内,如果是的话则增加n的值;然后再利用之前提到的面积比四分之Π与落入圆内点数与总点数之比构建等式,可以算出Π的近似值;在这里面仓颉的for循环在使用时,如果在for循环的循环体内不需要引用循环变量的话可以使用占位符来替代循环变量的。
在这里插入图片描述

基础数据类型

基本数据类型主要分常见的几种类型,在数组类型中分为两种,一种是Array是引用类型的数组,VArray是值类型的数组,在使用VArray时需要指定元素的个数,然后还提供了区间类型,可以在for循环时配合使用。
在这里插入图片描述

if表达式

然后就是常见的几种表达式,if表达式进行条件判断
在这里插入图片描述

while、dowhile循环

在这里插入图片描述

for in

for in的遍历,这里for 配合区间类型,从1到99取值 步长为2,然后for还可以将元组类型在定义循环变量时进行解构,也可以在循环体中无须引用循环变量时,可以使用通配符占位,然后还可以在for in的时候通过where引导一个bool表达式作为迭代元素的过滤器。
在这里插入图片描述

match 表达式

仓颉也提供了模式匹配表达式,运行时会先计算match括号中的表达式并获取到值,然后根据case进行匹配,如果成功会在执行完后退出match表达式,如果失败会继续匹配,然后还可以用或操作符连接多个类型的模式,如果待匹配值与任何一个模式匹配,就会执行case后的语句,并且还可以使用where 增加约束。
在这里插入图片描述

在这里插入图片描述

Option类型

在部分应用场景中,一个变量无法在整个生命周期内都被赋予有效值,例如存在异常情况或可选的初始化设计等,为了高效且安全地表达这种“或有或无”的值,仓颉语言提供了Option类型。在创建Option时,还可以在变量类型前加问号,快速表示Option类型,通过Option类型,强制开发者处理这种异常场景,让程序更加安全稳健。

函数定义

在仓颉中函数定义主要通过函数名、参数列表、返回值类型来定义的,参数分为普通参数和命名参数,命名参数在声明时必须在普通参数之后,可以为命名参数设置默认值,在传参时可以省略传参,对应的实参将取默认值。在仓颉中函数可以被调用也可以作为值去传递。
在这里插入图片描述

类的创建

接下来看一下仓颉中怎么创建类,创建类的方法是通过class关键字加类名的方式,然后类中可以定义成员变量、函数以及成员属性,同时具有private protected public static 这几种修饰符来控制访问的权限,然后同样的 静态成员函数只能引用静态成员。仓颉中支持使用 类来实现面向对象编程。仓颉中也有结构体的概念,类和结构体的整体结构类似使用struct 关键字进行定义,也具备自己的成员变量函数、属性以及对应的修饰符,但是class 与 struct 的主要区别在于:class 是引用类型,struct 是值类型,它们在赋值或传参时行为是不同的;class 之间可以继承,但 struct 之间不能继承。

在这里插入图片描述
在这里插入图片描述

继承

仓颉中类也只支持单继承,只有Open修饰的类可以被其他类继承,然后继承的方式是通过这个标志来标识的。
在这里插入图片描述

接口

接口使用关键字 interface 声明,其后是接口的名称 和接口的成员。在仓颉中继承和实现接口都是用同一个标志来表示。
在这里插入图片描述

在仓颉中如果一个类实现了多个接口,那么接口之间使用且符号来连接。
在这里插入图片描述

兼容

为了兼容已有的生态,仓颉支持调用 C 语言的函数,也支持 C 语言调用仓颉的函数。在仓颉中要调用 C 的函数,需要在仓颉语言中用 @C 和 foreign 关键字声明这个函数,但 @C 在修饰 foreign 声明的时候,可以省略。举个例子,假设我们要调用 C 的 rand 和 printf 函数,它的函数签名是这样的:
在这里插入图片描述
然后通过仓颉来调用是这样的。需要注意的是foreign 修饰函数声明,代表该函数为外部函数。被 foreign 修饰的函数只能有函数声明,不能有函数实现。foreign 声明的函数,参数和返回类型必须符合 C 和仓颉数据类型之间的映射关系。由于 C 侧函数很可能产生不安全操作,所以调用 foreign 修饰的函数需要被 unsafe 块包裹,否则会发生编译错误。@C 修饰的 foreign 关键字只能用来修饰函数声明,不可用来修饰其他声明,否则会发生编译错误。
在这里插入图片描述

未来规划

原生智能(AI Native)应用开发

在未来规划中,提到了将实现原生智能应用开发,虽然AI技术已被广泛普及和应用,但原生AI应用开发通常需要开发者具备较深的专业知识,并且面临一定的挑战,例如,学习曲线陡峭、集成复杂性等。常规的AI赋能是通过提供AI应用框架来实现,但是如果能在语言上提供更简洁的语法表达来降低开发者编写原生AI应用的门槛,则能让开发变得更加简单高效。因此仓颉借鉴web端和移动端的技术发展,希望通过DSL能力来构建类似AI领域的声明式范式。Agent DSL是我们现在正在畅想和尝试的AI原生能力,它是一种专为AI Agent开发和多Agent协同而设计的领域特定语言,是一种内嵌在仓颉语言中的DSL(即eDSL),开发者无需额外学习复杂的库和框架,通过DSL可以简单直观地使用AI功能。从代码段不难看出,在仓颉语言中对于Agent的声明和使用语法与仓颉本身语法一致,既能享受仓颉的静态检查能力,又不会给开发者带来额外的学习负担,充分发挥仓颉语言的高效编程、安全可靠的优势。Agent DSL不仅能让我们提升AI应用开发的效率,还能使代码更为准确地对应AI Agent的操作、决策过程。仓颉希望能达成高级抽象:Agent作为DSL中的内置语言抽象,其定义和描述更加自然直观、易于理解和维护。极简多Agent协同编程:通过流式符号抽象出不同的 Agent协同模式,开发者可以轻松地利用多 Agent 协作来开发智能化程度更高的应用。智能化开发工具链:基于Agent DSL,工具链为开发人员提供从应用开发到性能调测、调优的全方位智能支持。除了Agent DSL,原生AI应用框架也是仓颉正在构建的能力,通过语言原生以及框架的配合给开发者带来全场景智能化时代的应用编程新体验。
在这里插入图片描述

可视化并行并发程序调优

在这里插入图片描述
在这里插入图片描述
在未来规划中,还提到了可视化并行并发程序的调优,仓颉语言提供出色的并行并发模型,但开发者在使用并行并发模型开发过程中,经常会遇到一些“伪并行”、并行失效、并行等问题,往往需要花费大量时间去定位问题,效率低下。这时候就需要一个可视化并行并发调优工具能帮我们快速定位问题,支撑开发者在使用并行并发模型开发时,掌握并行调度的信息,找到并行调度的性能瓶颈。针对此,仓颉未来将提供可视化并行并发的调优工具,可以展示不同并发模式的Task统计信息,以及单个Task的运行情况,即Task调度的整个周期。可以选择不同并发模式,看到不同状态的Task的变化趋势以及数量,例如想知悉在一段时间内的运行任务数量,可以悬浮到相对应泳道,相对应的时间,即可看到确切数量;在Tasks泳道中选择不同的并发模式,可以看到相关的Task的生命周期信息,可直观看出多个Task之间的运行情况,帮助我们快速察觉并行并发问题。

如何试用

仓颉预览版的试用申请已经超过1.1万人,那么我们怎么去申请试用呢。
在这里插入图片描述
我们可以通过官网进行报名,在官网的最下方,有一个仓颉招募报名的入口,我们登录后点击这个入口,就会进入到报名的页面,也可以通过官方的公众号进行报名。

下载

现在是2025年10月,现在已经不需要申请试用了,已经可以直接在官网[https://cangjie-lang.cn/download]下载!
在这里插入图片描述

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐