一、引言

仓颉语言作为华为推出的新一代编程语言,具有诸多强大的特性。本文将带你快速入门仓颉语言,了解其基本概念、语法和应用。

仓颉语言是华为历经五年研发沉淀推出的编程语言,于 2024 年华为开发者大会上正式官宣。它主打原生智能化、天生全场景、高性能、强安全等特点,为开发者打造友好开发体验和卓越程序性能。

仓颉语言的名字来自 “仓颉造字”,寄托了团队希望该语言被广大开发者喜爱并广为流传的期望。其文件后缀名为.cj,以下是第一个入门代码输出:“你好,仓颉。”

仓颉语言具有高效的数据处理能力、强大的 AI 支持、高度可读的语法和广泛的跨平台支持等特性。在大数据分析和处理任务中,其独特的数据流模型允许开发者以声明式的方式编写数据处理逻辑,简化了代码的复杂度。同时,仓颉语言集成了先进的机器学习和深度学习框架,支持包括 TensorFlow 和 PyTorch 在内的主流 AI 工具,开发者可以通过简洁的语法定义和训练模型,快速实现智能应用。

仓颉语言采用了类似于自然语言的语法结构,使得代码更加直观和易读。无论是经验丰富的开发者还是初学者,都可以轻松上手,提高开发效率。此外,仓颉语言支持多种操作系统和硬件平台,包括 Windows、Linux、macOS 以及华为的自研操作系统 HarmonyOS,开发者可以在不同平台之间无缝迁移代码,实现真正的跨平台开发。

二、仓颉语言简介

仓颉语言是华为推出的面向全场景应用开发的现代编程语言。它有着深厚的背景,华为于 2019 年启动仓颉编程语言项目,历经五年精心研发,在 2024 年华为开发者大会上正式亮相。

其特点鲜明:

  • 原生智能化:内嵌 AgentDSL 的编程框架,实现自然语言与编程语言的有机融合。多 Agent 协同工作,简化符号表达,支持各类智能应用开发,模式可自由组合。
  • 天生全场景:采用轻量化可缩放运行时和模块化分层设计,即使在资源受限的设备上也能流畅运行。支持全场景领域扩展,通过元编程和 eDSL 技术,助力面向领域声明式开发。
  • 高性能:采用全并发 GC,应用线程运行更加流畅,响应速度更快。轻量化线程设计进一步提升了并发性能,降低了开发成本。
  • 强安全:将安全理念融入语言设计,帮助开发者专注于业务逻辑,减少安全漏洞的产生,实现 “编码即安全”。

仓颉语言的应用场景广泛,在大数据分析和处理任务中,其独特的数据流模型允许开发者以声明式的方式编写数据处理逻辑,简化代码复杂度。同时,集成了先进的机器学习和深度学习框架,支持包括 TensorFlow 和 PyTorch 在内的主流 AI 工具,开发者可以通过简洁的语法定义和训练模型,快速实现智能应用。此外,仓颉语言支持多种操作系统和硬件平台,包括 Windows、Linux、macOS 以及华为的自研操作系统 HarmonyOS,开发者可以在不同平台之间无缝迁移代码,实现真正的跨平台开发。

三、安装与环境配置

1. 获取 SDK

要获取仓颉编程语言通用版本 SDK,可以按照以下步骤进行:

  • 首先关注仓颉编程语言官方微信公众号,会收到自动推送消息,按照提示回复 SDK。
  • 然后填写试用问卷,等待仓颉编程语言官方邮箱回复邮件,官方会在 1 - 2 个工作日内回复。需要注意的是,仓颉编程语言 SDK 及开发工具存储在 GitCode Cangjie 社区上,Cangjie 社区会根据用户手机号通过审核,因此填写问卷时手机号需要与 GitCode 注册手机号保持一致,否则社区无法通过审核。
  • 根据仓颉编程语言官方邮件提示完成承诺函签署并回复邮件。
  • 最后仓颉编程语言官方邮箱会再次回复邮件。此时,仓颉编程语言社区运营在 GitCode Cangjie 社区上,点击链接才能申请加入社区。

2. 安装插件

以 Windows 平台为例,在 GitCode Cangjie 社区下载仓颉 VScode 插件后,进行以下操作:

  • 找到下载的插件文件,如果是压缩包则进行解压操作。
  • 在解压后的文件中找到.vsix 文件。
  • 打开 VSCode,点击左侧 “Extensions -> Views and More Actions -> Install from VSIX”,找到刚才解压出来的.vsix 文件进行安装。安装成功后,可在左侧 “Extensions -> Cangjie -> 齿轮图标 -> settings” 中进行配置。在 “Cangjie Sdk Path: CJNative Backend” 中填入步骤 1 中安装的仓颉 SDK 路径(如 “D:\Code\cangjiesdk\cangjie”,根据实际情况填写)。

3. 创建项目

在 VScode 中创建仓颉项目的步骤如下:

  • 按 Ctrl + Shift + P 打开 VScode 功能搜索框,输入 “Create Cangjie Project” 就可以找到创建仓颉项目的选项。
  • 下一步选择 “Create CJNative Cangjie Project”。
  • 再下一步选择 “Create Executable Output Cangjie Project”。
  • 弹出窗里选择工程存放的目录文件夹。
  • 回到之前界面,在上方输入框中输入工程的名称,并回车。
  • 在左侧目录结构中找到 “src -> main.cj”,可以看到默认创建的一段 “helloworld” 代码。
  • 编辑器右上方三角按钮编译并输出代码,自动弹出 TERMINAL 显示打印结果。

四、基本概念

1.Hello World

展示如何编写第一个仓颉程序,输出 “你好,仓颉!”。

以下是一个简单的仓颉程序,输出 “你好,仓颉!”:


main() {

println("你好,仓颉!")

}

2. 标识符

包括普通变量、原始表示符等的使用方法。

在仓颉编程语言中,标识符分为普通标识符和原始标识符两类。普通标识符不能和仓颉关键字相同,可以取自以下两类字符序列:

  1. 由英文字母开头,后接零至多个英文字母、数字或下划线 “_”。例如:abc_abc、abc_a1b2c3、a_b_c、a1_b2_c3。
  1. 由一至多个下划线 “” 开头,后接一个英文字母,最后可接零至多个英文字母、数字或下划线 “”。

原始标识符是在普通标识符或仓颉关键字的外面加上一对反引号,主要用于将仓颉关键字作为标识符的场景。例如:abc、_abc、a1b2c3、if、while。

以下是一个示例程序:


main() {

// 普通变量

let num = 10

let ___x = "___Str"

println(num)

println(___x)

// 原始表示符

// 用于将关键字作为标识符

let `for` = "这是一个将for关键字用作原始标识符"

println(`for`)

}

3. 内置类型

介绍各种字面量后缀、字符类型、字符串、数组、元组、区间类型等。

在仓颉编程语言中,有以下内置类型:

  1. 字面量后缀
    • 整形:Int8 -> i8、Uint8 -> u8 等。
    • 浮点型:Float16 -> f16。
  1. 字符类型:表示一个 unicode 字符,可以用单引号括起来。例如:let e: Rune = ' 仓 ';let f: Rune = '\u {9889}'。
  1. 字符串
    • 单行字符串:let g: String = "Cang" + "jie"。
    • 多行字符串:let h: String = """ 第 1 行,这是多行字符串

第 2 行 """。

    • 插值字符串:要求表达式类型实现了 ToString 接口。例如:let i: String = "Cangjie${a}"。
  1. 数组
    • 引用类型数组:let j: Array<UInt8> = [1u8, 2u8]。
    • 值类型数组:let k: VArray<Rune, $2> = [e, f]。
  1. 元组类型:let l: (Int64, Float64) = (2024, 9.6)。
  1. 区间类型:主要用于 for in 表达式中。let m: Range<Int64> = 2019..2024。

4.if 表达式

通过示例讲解类似 gcc 中的大括号表达式的 if 表达式的用法。

仓颉语言中的 if 表达式用于根据条件的值来决定是否执行相关代码逻辑。if 表达式有三种形式:单分支的 if 表达式、双分支的 if 表达式和嵌套的 if 表达式。

单分支的 if 表达式

单分支的 if 表达式只有一个分支,其语法如下:


if (条件) {

代码块

}

其中的条件必须是一个布尔类型的表达式,由一对匹配的花括号包围代码块。执行时,首先测试条件的值,如果条件为 true,就执行括号内的代码块;否则,不执行任何代码。例如:


// isScorePassed 表示分数是否合格,true 表示合格,false 表示不合格

if (isScorePassed) {

println("合格")

}

println("执行完毕")

在上述代码中,isScorePassed 为 true 时,将输出:合格执行完毕。如果 isScorePassed 为 false,则只会输出:执行完毕。这表明,单分支的 if 表达式是否会执行代码,完全取决于条件的取值。值得注意的是,if 表达式的类型为 Unit,其值为 0。

双分支的 if 表达式

双分支的 if 表达式包含两个分支,语法如下:


if (条件) {

代码块1

} else {

代码块2

}

在执行时,如果条件为 true,执行代码块 1;如果条件为 false,则执行代码块 2。例如:


if (isScorePassed) {

println("合格")

} else {

println("不合格")

}

println("执行完毕")

如果 isScorePassed 为 true,输出结果为:合格执行完毕。如果 isScorePassed 为 false,输出结果为:不合格执行完毕。这里,else 分支必须在 if 表达式之后的代码中运行。

双分支 if 表达式的类型

当 if 表达式的值被使用时,双分支的 if 表达式的类型是 if 分支和 else 分支类型的最小公共父类。例如:


main() {

var creditScore: UInt16 = 800

var interestRate: Float64 = if (creditScore >= 600) {

0.06

} else {

0.08

}

println(interestRate)

}

在这个例子中,interestRate 的值是根据 creditScore 的值决定的。如果 creditScore 大于或等于 600,则利率为 0.06;否则,利率为 0.08。最终输出利率的结果。

嵌套的 if 表达式

当希望匹配更多的条件时,可以使用嵌套的 if 表达式。嵌套 if 表达式可以包含多个分支。其语法结构如下:


if (条件1) {

代码块1

} else if (条件2) {

代码块2

}...else {

代码块n

}

其中每个条件都必须是布尔类型的表达式。整个 if 表达式的执行流程如下:测试条件 1 的值,如果为 true,执行代码块 1,整个 if 表达式结束;如果条件 1 为 false,测试条件 2 的值,以此类推,直到找到为 true 的条件;如果所有条件都为 false,则执行 else 分支中的代码块。例如:


if (creditScore < 600) {

interestRate = 0.08

} else if (creditScore < 800) {

interestRate = 0.06

} else {

interestRate = 0.05

}

println(interestRate)

根据 creditScore 的值,选择执行不同的分支,最终输出相应的利率。

if 表达式中的类型推断

在某些情况下,if 表达式不仅用于条件分支选择,还可以返回值。此时,if 表达式的返回值类型由 if 和 else 分支的类型决定。例如,以下代码会根据 creditScore 的值,推断出 interestRate 的类型:


main() {

var creditScore: UInt16 = 800

var interestRate: Float64 = if (creditScore >= 600) {

0.06

} else {

0.08

}

println(interestRate)

}

在这个例子中,interestRate 的类型被推断为 Float64,因为 if 和 else 分支中的返回值都是浮点数。这种情况适用于条件表达式需要返回一个值的场景。

嵌套 if 表达式中的执行顺序

嵌套的 if 表达式可以根据多个条件执行不同的逻辑。例如,以下代码展示了如何根据不同的 creditScore 值调整利率:


if (creditScore < 600) {

interestRate = 0.08

} else if (creditScore < 800) {

interestRate = 0.06

} else if (creditScore < 1000) {

interestRate = 0.05

} else {

interestRate = 0.04

}

在这个例子中,程序将依次测试 creditScore 是否满足每个条件,直到找到符合条件的分支。如果 creditScore 小于 600,利率设置为 0.08;如果小于 800,但大于等于 600,利率为 0.06,以此类推。最终的输出结果取决于条件的匹配情况。

条件表达式的最佳实践

对于 if 表达式的使用,编写整洁的代码并避免重复是非常重要的。例如,如果条件非常复杂,可以通过添加额外的条件块减少不必要的代码重复,确保代码逻辑清晰。例如:


if (creditScore <= 1000) {

if (creditScore < 600) {

interestRate = 0.08

} else if (creditScore < 800) {

interestRate = 0.06

} else if (creditScore < 900) {

interestRate = 0.05

} else {

interestRate = 0.04

}

} else {

println("数据错误!")

}

这种写法将不同的条件组合在一起,确保只有在 creditScore 小于等于 1000 时才会进入利率设置的逻辑,如果超出此范围,将输出错误信息。这是一种防止数据错误的良好实践。

5.for 表达式

分别介绍不同形式的 for 循环,如范围循环、元组解构循环、占位符循环和条件循环。

在仓颉编程语言中,for 表达式有多种形式:

  1. 范围循环

var sum = 0

for (i in 1..99 : 2) {

sum += i

}

println(sum)

  1. 元组解构循环

let arr = [(1,2), (3, 4)]

for ((x, y) in arr) {

println("x=${x} y=${y}")

}

  1. 占位符循环

var num = 2

for (_ in 0..5) {

num *= num

}

  1. 条件循环

for (i in 0..10 where i % 2 == 1) {

println(i)

}

6.while 表达式

展示如何使用 while 循环进行数值计算。

while 表达式的基本形式为:


while (条件) {

循环体

}

例如,以下程序使用 while 表达式,基于二分法,近似计算数字 2 的平方根:


main() {

var root = 0.0

var min = 1.0

var max = 2.0

var error = 1.0

let tolerance = 0.1**10

while (error**2 > tolerance) {

root = (min + max) / 2.0

error = root**2 - 2.0

if (error > 0.0) {

max = root

} else {

min = root

}

}

println("2 的平方根约等于:${root}")

}

7.demo 手动计算 Π

讲解如何在正方形中随机投点手动计算圆周率,但可能在在线编译器中运行失败。

以下是手动计算圆周率的示例程序:


import std.random.*

import std.math.*

main() {

/**

* 手动计算圆周率

* 在一个正方形中随机投点

*/

const N = 10000

var n: UInt32 = 0

let random = Random()

for (_ in 0..N) {

let x = random.nextFloat64()

let y = random.nextFloat64()

if ((x - 0.5)**2 + (y - 0.5)**2 < 0.25) {

n++

}

}

let pi = Float64(n) / Float64(N) * 4.0

println("Π = ${pi}")

println("deviation: ${abs(Float64.PI - pi)}")

}

五、函数

1. 普通函数

在仓颉语言中,普通函数可以用于实现各种复杂的逻辑。以二叉树的中序遍历为例,我们可以定义一个函数来遍历二叉树的节点。

首先,定义一个节点函数,接受一个值和左右子节点的函数:


func node(value: Int32, left!: () -> Unit = void, right!: () -> Unit = void) {

// 二叉树的中序遍历

func show() {

left()

print(value)

right()

}

return show

}

在主函数中,可以使用这个节点函数来构建一个二叉树并进行遍历:


main() {

let tree = node(0, left: node(1, left: node(2, right: node(3))), right: node(4, left: node(5), right: node(6)))

tree()

}

通过这种方式,我们可以方便地定义和使用普通函数来处理二叉树等数据结构。

2.lambda

在仓颉语言中,lambda 表达式是一种简洁的函数定义方式。它可以用于定义匿名函数,并且可以作为参数传递给其他函数或者赋值给变量。

lambda 表达式的语法为 { p1: T1,..., pn: Tn => expressions | declarations }。其中,=> 之前为参数列表,多个参数之间使用 , 分隔,每个参数名和参数类型之间使用 : 分隔。=> 之后为 lambda 表达式体,是一组表达式或声明序列。

例如,定义一个接受两个参数并返回它们和的 lambda 表达式:


let f1 = { a: Int64, b: Int64 => a + b }

无参数的 lambda 表达式也可以定义,如下:


var display = { => println("Hello") }

lambda 表达式可以直接调用,也可以赋值给变量再调用。例如:


let r1 = { a: Int64, b: Int64 => a + b }(1,2) // r1=3

let r2 = { => 123 }() // r2=123

lambda 表达式作为参数使用时,其参数类型根据使用处所在的函数调用的形参类型推断。例如:


func f(a1: (Int64) -> Int64): Int64 {

a1(1)

}

main() {

f({ a2 => a2 + 10 })

}

lambda 表达式作为返回值使用时,其返回类型根据使用处所在函数的返回类型推断。例如:


func f(): (Int64) -> Int64 {

{ a: Int64 => a }

}

lambda 表达式中不支持声明返回类型,其返回类型总是从上下文中推断出来,若无法推断则报错。若上下文明确指定了 lambda 表达式的返回类型,则其返回类型为上下文指定的类型。

六、结语

仓颉语言作为华为推出的新一代编程语言,为编程之路开启了新的篇章。通过本文的介绍,我们了解了仓颉语言的基本概念、语法和应用,包括安装与环境配置、基本概念、函数等方面的内容。

仓颉语言的入门要点总结如下:首先,要了解仓颉语言的背景和特点,认识到其在原生智能化、天生全场景、高性能、强安全等方面的优势。其次,掌握安装与环境配置的方法,包括获取 SDK、安装插件和创建项目。在学习基本概念时,要熟悉 Hello World 程序、标识符、内置类型、if 表达式、for 表达式、while 表达式和手动计算圆周率等内容。函数部分则包括普通函数和 lambda 的使用方法。

对于想要深入学习仓颉语言的读者,建议多实践、多探索。可以通过参与实际项目、阅读官方文档和参与社区讨论等方式,不断提升自己的编程技能。同时,也可以关注仓颉语言的发展动态,了解其新特性和优化,为自己的编程之路增添更多的可能性。

总之,仓颉语言为开发者提供了一个强大而灵活的编程工具,鼓励读者勇敢地迈出第一步,深入学习和探索仓颉语言,开启编程之旅的新篇章。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐