文章目录
- 前言
- [一、环境搭建(5 分钟)](#一、环境搭建(5 分钟))
-
- 1.1、开发工具选择与安装
- [1.2、Hello World 程序实战](#1.2、Hello World 程序实战)
- [二、基础语法(10 分钟)](#二、基础语法(10 分钟))
-
- 2.1、变量声明与作用域
- 2.2、基本数据类型详解
- 2.3、运算符与表达式
- 2.4、控制流语句
-
- [2.4.1、if-else 条件语句](#2.4.1、if-else 条件语句)
- [2.4.2、match 模式匹配](#2.4.2、match 模式匹配)
- 2.4.3、循环语句
- [三、函数(5 分钟)](#三、函数(5 分钟))
-
- 3.1、函数定义与参数
- [3.2、Lambda 表达式与闭包](#3.2、Lambda 表达式与闭包)
- [四、数据结构(5 分钟)](#四、数据结构(5 分钟))
-
- 4.1、数组基础操作
- [4.2、ArrayList 动态数组](#4.2、ArrayList 动态数组)
- [4.3、HashMap 键值对存储](#4.3、HashMap 键值对存储)
- [五、面向对象(5 分钟)](#五、面向对象(5 分钟))
- [六、可空类型与错误处理(3 分钟)](#六、可空类型与错误处理(3 分钟))
-
- 6.1、可空类型与空安全
- [6.2、Result 类型错误处理](#6.2、Result 类型错误处理)
- 6.3、异常捕获与处理
- [七、实用示例(2 分钟)](#七、实用示例(2 分钟))
- 八、常见问题与技巧
- 九、学习路线建议
- 十、快速参考卡片
-
- 10.1、语法快速参考
- [10.2、常用 API 参考](#10.2、常用 API 参考)
- 十一、关于作者与学习资源
- 总结
前言
2024 年 10 月底华为发布仓颉编程语言,作为大数据开发工程师和 CSDN 成都站主理人,我意识到这是抓住新语言红利期的机会。HDC 2024 大会上仓颉的性能和安全性演示让我印象深刻,社区成员对仓颉学习需求很大,每周都有人问我如何入门。11 月 4 日开始学习之旅,两个月里我不仅系统学习了仓颉,还帮助 15 位朋友成功入门,在这个过程中总结出一套高效的学习方法。本文目标是让开发者在 30 天内从零基础到能够独立开发简单应用,通过实际代码示例而非枯燥理论讲解,配合详细注释和常见问题解答,采用循序渐进的方式从基础语法到面向对象再到实战项目,帮助你快速建立对这门语言的整体认知并掌握核心开发技能,为深入学习和实战开发打下坚实基础。

声明:本文由作者"白鹿第一帅"于 CSDN 社区原创首发,未经作者本人授权,禁止转载!爬虫、复制至第三方平台属于严重违法行为,侵权必究。亲爱的读者,如果你在第三方平台看到本声明,说明本文内容已被窃取,内容可能残缺不全,强烈建议您移步"白鹿第一帅" CSDN 博客查看原文,并在 CSDN 平台私信联系作者对该第三方违规平台举报反馈,感谢您对于原创和知识产权保护做出的贡献!
文章作者 :白鹿第一帅,作者主页 :https://blog.csdn.net/qq_22695001,未经授权,严禁转载,侵权必究!
一、环境搭建(5 分钟)
我的环境搭建经历(Day 1,11 月 4 日) ,学习任何编程语言的第一步都是搭建开发环境。我在 11 月 4 日开始学习仓颉时,环境搭建花了我整整一个下午。不是因为难,而是因为选择太多,不知道该用哪种方式。选择困难症:IDE 还是命令行?
编程初学者 有经验开发者 喜欢图形界面 喜欢命令行 开发工具选择 你的经验? DevEco Studio 偏好? 命令行工具 优势 代码提示 可视化调试 项目管理 插件生态 优势 轻量快速 脚本自动化 远程开发
开发工具对比
| 特性 | DevEco Studio | 命令行工具 | 推荐人群 |
|---|---|---|---|
| 学习曲线 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 初学者 vs 老手 |
| 代码提示 | ✅ 完善 | ❌ 无 | 需要提示的开发者 |
| 调试功能 | ✅ 可视化 | ⚠️ 命令行 | 需要调试的项目 |
| 启动速度 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 快速验证代码 |
| 项目管理 | ✅ 完善 | ⚠️ 手动 | 大型项目 |
| 资源占用 | 2GB+ | <100MB | 配置较低的电脑 |
| 适合场景 | 完整项目开发 | 快速脚本验证 | - |
最初我纠结于两个选择:
- 使用 DevEco Studio(图形化 IDE,功能强大)
- 使用命令行工具(轻量级,适合老手)
作为一个习惯用 VSCode 的开发者,我最初想用命令行工具。但尝试后发现,DevEco Studio 的代码提示、调试功能、项目管理都很完善,特别适合初学者。最终我选择了 DevEco Studio,这个决定让我后续的学习效率提升了很多。
给初学者的建议:
- 如果你是编程初学者,强烈推荐 DevEco Studio
- 如果你有丰富的编程经验,可以尝试命令行工具
- 两种方式可以并存,根据场景选择
1.1、开发工具选择与安装
方式一:使用 DevEco Studio(推荐初学者),DevEco Studio 是华为官方提供的集成开发环境,专为鸿蒙和仓颉开发设计。它提供了代码补全、语法高亮、调试工具、项目管理等功能,大大提升开发效率。
安装步骤:
- 访问华为开发者官网,下载 DevEco Studio
- 安装完成后,打开 IDE,在插件市场搜索"Cangjie"
- 安装仓颉插件,重启 IDE
- 创建新项目:File -> New -> Cangjie Project
我的安装经验:
我 下载阶段 下载阶段 我 访问官网 访问官网 我 下载安装包 下载安装包 我 等待下载完成 等待下载完成 安装阶段 安装阶段 我 运行安装程序 运行安装程序 我 选择安装路径 选择安装路径 我 等待安装 等待安装 配置阶段 配置阶段 我 首次启动 首次启动 我 下载SDK 下载SDK 我 安装插件 安装插件 我 配置完成 配置完成 DevEco Studio 安装历程
| 步骤 | 时间 | 注意事项 |
|---|---|---|
| 下载安装包 | 10-30 分钟 | 约 2GB,需要预留足够空间 |
| 安装程序 | 5-10 分钟 | 选择合适的安装路径 |
| 首次启动 | 2-3 分钟 | 会进行初始化配置 |
| 下载 SDK | 10-15 分钟 | 建议配置国内镜像源 |
| 安装插件 | 3-5 分钟 | 搜索"Cangjie"插件 |
| 总计 | 30-60 分钟 | 一次性投入,后续高效 |
- 下载大小约 2GB,需要预留足够空间
- 首次启动会下载 SDK,需要等待 10-15 分钟
- 建议配置国内镜像源,加快下载速度
方式二:使用命令行工具(适合有经验的开发者),命令行工具轻量级,启动快,适合快速验证代码。如果你习惯用 Vim、Emacs 或 VSCode,可以选择这种方式。
bash
# 安装仓颉编译器(通过DevEco Studio)
# 请访问华为开发者官网下载DevEco Studio
# https://developer.huawei.com/consumer/cn/deveco-studio/
# 验证安装
cjc --version
# 创建新项目
cjc new hello-cangjie
cd hello-cangjie
1.2、Hello World 程序实战
Hello World 的意义(Day 1 下午),写第一个程序时,我很激动。虽然只是简单的"Hello World",但它标志着学习的开始。很多人觉得 Hello World 没意义,但我认为它很重要:
- 验证环境搭建是否成功
- 熟悉编译和运行流程
- 建立信心,迈出第一步
我的第一次尝试 ,创建 main.cj 文件:
cangjie
// 这是注释
main() {
println("你好,仓颉!")
println("Hello, Cangjie!")
}
代码说明:
main():程序的入口函数,类似 Java 的 main 方法println():打印函数,会自动换行//:单行注释,编译器会忽略- 字符串用双引号包裹,支持中文
运行程序:
bash
cjc run main.cj
输出:
你好,仓颉!
Hello, Cangjie!
第一次运行的感受,当我看到输出时,虽然只是两行文字,但心里很有成就感。这说明环境搭建成功了,我可以开始真正的学习了。
cjc run 编译失败 修复错误 编译成功 成功! 编写代码 编译 检查错误 运行 查看输出 常见错误:
- 语法错误
- 拼写错误
- 编码问题
常见问题:
- 如果提示"cjc: command not found",说明环境变量没配置好
- 如果提示编译错误,检查代码是否有拼写错误
- 如果中文显示乱码,检查文件编码是否为 UTF-8
二、基础语法(10 分钟)
学习方法建议(Day 2-5,11 月 5-8 日),基础语法是学习的重点,也是最容易放弃的阶段。很多人觉得语法枯燥,看了就忘。我的经验是:不要死记硬背,要通过实践来学习。
我的学习方法:
否 是 看语法点 写代码验证 理解了吗? 写更多例子 记录笔记 第二天复习 进入下一个
- 看一个语法点,立即写代码验证
- 不理解的地方,写多个例子尝试
- 每天学习 2-3 个语法点,不贪多
- 第二天复习前一天的内容
学习效果对比
| 学习方式 | 记忆效果 | 理解深度 | 时间投入 | 推荐度 |
|---|---|---|---|---|
| 只看不练 | ⭐⭐ | ⭐⭐ | 1 小时/天 | ❌ |
| 看完就练 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 2 小时/天 | ✅ |
| 大量练习 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 3 小时/天 | ✅✅ |
这个方法让我在 4 天内掌握了基础语法,而且记得很牢。
2.1、变量声明与作用域
变量是什么?(Day 2 上午),变量就是存储数据的容器。学习变量时,我最初不理解 let 和 var 的区别,写了很多代码才明白:
let:声明不可变变量,一旦赋值就不能改变var:声明可变变量,可以多次赋值
为什么要区分可变和不可变? 这是我学习仓颉时的第一个困惑。后来我理解了:
- 不可变变量更安全,不会被意外修改
- 不可变变量便于编译器优化
- 函数式编程推荐使用不可变变量
在实际开发中,我发现 80% 的变量都可以用 let,只有需要修改的才用 var。这让代码更安全、更易维护。
cangjie
main() {
// 使用 let 声明不可变变量(推荐)
let name: String = "张三"
let age: Int64 = 25
// 类型推断(编译器自动推断类型)
let city = "北京" // 自动推断为 String
let score = 95 // 自动推断为 Int64
// 使用 var 声明可变变量
var count = 0
count = count + 1 // 可以修改
println("姓名: ${name}, 年龄: ${age}")
println("城市: ${city}, 分数: ${score}")
println("计数: ${count}")
}
关键点:
let声明不可变变量(类似 Java 的 final)var声明可变变量- 支持类型推断,可以省略类型声明
- 使用
${变量}进行字符串插值
2.2、基本数据类型详解
数据类型的重要性(Day 2 下午),学习数据类型时,我最初觉得很无聊:为什么要区分 Int8、Int16、Int32、Int64?直接用一个 Int 不行吗?
后来我理解了:不同的数据类型占用不同的内存空间。Int8 只占 1 字节,Int64 占 8 字节。在处理大量数据时,选择合适的类型可以节省内存。
在我的大数据项目中,有一个字段存储年龄(0-120)。如果用 Int64,每个值占 8 字节;如果用 Int8,只占 1 字节。处理 1 亿条数据时,可以节省 700MB 内存!
类型选择建议:
| 数据类型 | 内存占用 | 数值范围 | 适用场景 | 示例 |
|---|---|---|---|---|
| Int8 | 1 字节 | -128~127 | 年龄、等级 | 年龄: 25 |
| Int16 | 2 字节 | -32768~32767 | 端口号、计数 | 端口: 8080 |
| Int32 | 4 字节 | -21 亿~21 亿 | ID、数量 | 用户 ID |
| Int64 | 8 字节 | 超大范围 | 默认整数 | 时间戳 |
| Float32 | 4 字节 | 7 位精度 | 一般小数 | 温度: 25.5 |
| Float64 | 8 字节 | 15 位精度 | 默认小数 | 科学计算 |
| Bool | 1 字节 | true/false | 开关状态 | 是否登录 |
| String | 可变 | 任意文本 | 文本数据 | 用户名 |
cangjie
main() {
// 整数类型
let int8: Int8 = 127 // 8位整数
let int16: Int16 = 32767 // 16位整数
let int32: Int32 = 2147483647 // 32位整数
let int64: Int64 = 9223372036854775807 // 64位整数(默认)
// 浮点类型
let float32: Float32 = 3.14
let float64: Float64 = 2.718281828 // 默认浮点类型
// 布尔类型
let isStudent: Bool = true
let isGraduated: Bool = false
// 字符和字符串
let char: Rune = 'A' // 单个字符(Unicode)
let text: String = "仓颉语言"
// 类型转换
let num = 42
let numFloat = Float64(num) // 显式转换
let numStr = num.toString() // 转为字符串
println("整数: ${int64}")
println("浮点: ${float64}")
println("布尔: ${isStudent}")
println("字符串: ${text}")
}
2.3、运算符与表达式
cangjie
main() {
// 算术运算符
let a = 10
let b = 3
println("加法: ${a + b}") // 13
println("减法: ${a - b}") // 7
println("乘法: ${a * b}") // 30
println("除法: ${a / b}") // 3
println("取模: ${a % b}") // 1
// 比较运算符
println("相等: ${a == b}") // false
println("不等: ${a != b}") // true
println("大于: ${a > b}") // true
println("小于: ${a < b}") // false
println("大于等于: ${a >= b}") // true
println("小于等于: ${a <= b}") // false
// 逻辑运算符
let x = true
let y = false
println("与: ${x && y}") // false
println("或: ${x || y}") // true
println("非: ${!x}") // false
// 位运算符
let m = 5 // 二进制: 0101
let n = 3 // 二进制: 0011
println("按位与: ${m & n}") // 1 (0001)
println("按位或: ${m | n}") // 7 (0111)
println("按位异或: ${m ^ n}") // 6 (0110)
println("左移: ${m << 1}") // 10 (1010)
println("右移: ${m >> 1}") // 2 (0010)
}
2.4、控制流语句
控制流语句决定程序的执行顺序,是编程的核心概念。仓颉提供了丰富的控制流语句,包括条件判断、循环、跳转等。
控制流的重要性:
- 逻辑控制:根据条件执行不同的代码分支
- 重复执行:使用循环处理批量数据
- 程序结构:让程序逻辑更清晰
- 效率提升:避免重复编写相似代码
2.4.1、if-else 条件语句
cangjie
main() {
let score = 85
// 基本 if-else
if (score >= 90) {
println("优秀")
} else if (score >= 80) {
println("良好")
} else if (score >= 60) {
println("及格")
} else {
println("不及格")
}
// if 表达式(可以返回值)
let grade = if (score >= 60) { "通过" } else { "未通过" }
println("结果: ${grade}")
// 简洁写法
let status = if (score >= 60) "及格" else "不及格"
println("状态: ${status}")
}
2.4.2、match 模式匹配
cangjie
main() {
let day = 3
// 基本 match
match (day) {
case 1 => println("星期一")
case 2 => println("星期二")
case 3 => println("星期三")
case 4 => println("星期四")
case 5 => println("星期五")
case 6 | 7 => println("周末") // 多个值
case _ => println("无效") // 默认分支
}
// match 表达式
let dayName = match (day) {
case 1 => "Monday"
case 2 => "Tuesday"
case 3 => "Wednesday"
case 4 => "Thursday"
case 5 => "Friday"
case 6 | 7 => "Weekend"
case _ => "Invalid"
}
println("Day: ${dayName}")
}
2.4.3、循环语句
cangjie
main() {
// for 循环(范围)
println("=== for 循环 ===")
for (i in 0..5) { // 0 到 4
println("i = ${i}")
}
// for 循环(包含结束值)
for (i in 0..=5) { // 0 到 5
println("i = ${i}")
}
// for 循环(步长)
for (i in 0..10 step 2) { // 0, 2, 4, 6, 8
println("i = ${i}")
}
// 遍历数组
let fruits = ["苹果", "香蕉", "橙子"]
for (fruit in fruits) {
println("水果: ${fruit}")
}
// while 循环
println("=== while 循环 ===")
var count = 0
while (count < 3) {
println("count = ${count}")
count += 1
}
// do-while 循环
println("=== do-while 循环 ===")
var num = 0
do {
println("num = ${num}")
num += 1
} while (num < 3)
// break 和 continue
println("=== break 和 continue ===")
for (i in 0..10) {
if (i == 3) {
continue // 跳过 3
}
if (i == 7) {
break // 在 7 处停止
}
println("i = ${i}")
}
}
三、函数(5 分钟)
函数的本质(Day 6-7,11月 9-10 日),学习函数时,我终于理解了编程的精髓:复用。函数就是把重复的代码封装起来,需要时调用,避免重复编写。
代码对比:重复 vs 函数
函数方式 重复代码方式 定义 printSum 函数 调用 printSum10,20 调用 printSum30,40 调用 printSum50,60 打印结果 计算 10+20 打印结果 计算 30+40 打印结果 计算 50+60
Day 6 上午,我写了一个计算器程序,代码重复严重:
cangjie
// 重复的代码
let result1 = 10 + 20
println("10 + 20 = ${result1}")
let result2 = 30 + 40
println("30 + 40 = ${result2}")
let result3 = 50 + 60
println("50 + 60 = ${result3}")
Day 6 下午,我学会了函数,代码简洁多了:
cangjie
func printSum(a: Int64, b: Int64) {
println("${a} + ${b} = ${a + b}")
}
printSum(10, 20)
printSum(30, 40)
printSum(50, 60)
这个对比让我深刻理解了函数的价值。函数的好处:
| 对比项 | 不使用函数 | 使用函数 | 改进 |
|---|---|---|---|
| 代码行数 | 15 行 | 7 行 | ⬇️ 53% |
| 重复代码 | 3 处 | 0 处 | ⬇️ 100% |
| 维护成本 | 修改 3 处 | 修改 1 处 | ⬇️ 67% |
| 可读性 | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⬆️ 150% |
| 可测试性 | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⬆️ 150% |
3.1、函数定义与参数
函数的组成部分,一个完整的函数包含:
- 函数名:描述函数的功能
- 参数列表:函数需要的输入
- 返回类型:函数的输出类型
- 函数体:具体的实现逻辑
命名建议:
| 规范 | 好的示例 | 不好的示例 | 说明 |
|---|---|---|---|
| 动词开头 | getUserName() | userName() | 表明这是一个动作 |
| 有意义 | calculateTotalScore() | calc() | 清晰表达功能 |
| 驼峰命名 | printStudentInfo() | print_student_info() | 遵循语言规范 |
| 避免缩写 | getMaximumValue() | getMaxVal() | 完整单词更清晰 |
- 使用动词开头:get、set、calculate、print
- 名称要有意义:getUserName 而不是 getName
- 遵循驼峰命名:calculateTotalScore
cangjie
// 基本函数
func greet(name: String): Unit {
println("你好, ${name}!")
}
// 带返回值的函数
func add(a: Int64, b: Int64): Int64 {
return a + b
}
// 表达式函数(单行)
func multiply(a: Int64, b: Int64): Int64 = a * b
// 默认参数
func power(base: Int64, exponent: Int64 = 2): Int64 {
var result: Int64 = 1
for (_ in 0..exponent) {
result *= base
}
return result
}
// 可变参数
func sum(numbers: Int64...): Int64 {
var total: Int64 = 0
for (num in numbers) {
total += num
}
return total
}
main() {
greet("张三")
let result1 = add(10, 20)
println("10 + 20 = ${result1}")
let result2 = multiply(5, 6)
println("5 * 6 = ${result2}")
println("2^2 = ${power(2)}") // 使用默认参数
println("2^3 = ${power(2, 3)}") // 指定参数
println("总和: ${sum(1, 2, 3, 4, 5)}")
}
3.2、Lambda 表达式与闭包
cangjie
main() {
// Lambda 表达式
let square = { x: Int64 => x * x }
println("5的平方: ${square(5)}")
// 多参数 Lambda
let add = { x: Int64, y: Int64 => x + y }
println("3 + 7 = ${add(3, 7)}")
// 高阶函数
func applyOperation(a: Int64, b: Int64, op: (Int64, Int64) -> Int64): Int64 {
return op(a, b)
}
let result1 = applyOperation(10, 5, { x, y => x + y })
let result2 = applyOperation(10, 5, { x, y => x - y })
let result3 = applyOperation(10, 5, { x, y => x * y })
println("10 + 5 = ${result1}")
println("10 - 5 = ${result2}")
println("10 * 5 = ${result3}")
}
四、数据结构(5 分钟)
4.1、数组基础操作
cangjie
main() {
// 创建数组
let numbers = [1, 2, 3, 4, 5]
let fruits = ["苹果", "香蕉", "橙子"]
// 访问元素
println("第一个数字: ${numbers[0]}")
println("第二个水果: ${fruits[1]}")
// 数组长度
println("数组长度: ${numbers.size}")
// 修改元素(需要 var)
var mutableArray = [10, 20, 30]
mutableArray[0] = 15
println("修改后: ${mutableArray[0]}")
// 数组方法
let doubled = numbers.map({ x => x * 2 })
println("翻倍: ${doubled}")
let evens = numbers.filter({ x => x % 2 == 0 })
println("偶数: ${evens}")
let sum = numbers.reduce(0, { acc, x => acc + x })
println("总和: ${sum}")
}
4.2、ArrayList 动态数组
cangjie
main() {
// 创建 ArrayList
var list = ArrayList<Int64>()
// 添加元素
list.append(10)
list.append(20)
list.append(30)
println("列表: ${list}")
println("大小: ${list.size}")
// 插入元素
list.insert(1, 15) // 在索引1处插入15
println("插入后: ${list}")
// 删除元素
list.remove(2)
println("删除后: ${list}")
// 遍历
for (item in list) {
println("元素: ${item}")
}
}
4.3、HashMap 键值对存储
cangjie
main() {
// 创建 HashMap
var scores = HashMap<String, Int64>()
// 添加键值对
scores["张三"] = 95
scores["李四"] = 87
scores["王五"] = 92
// 获取值
if (let score = scores["张三"]) {
println("张三的分数: ${score}")
}
// 检查键是否存在
if (scores.containsKey("李四")) {
println("李四的成绩已录入")
}
// 遍历
for ((name, score) in scores) {
println("${name}: ${score}分")
}
// 删除
scores.remove("王五")
println("删除后大小: ${scores.size}")
}
五、面向对象(5 分钟)
面向对象的顿悟时刻(Day 11-13,11 月 14-16 日),学习面向对象时,我经历了从困惑到顿悟的过程。最初我不理解:为什么要用类?函数不够用吗?
我的理解过程:
我 上午 上午 我 用函数实现学生管理 用函数实现学生管理 我 发现数据分散问题 发现数据分散问题 我 感到困惑 感到困惑 下午 下午 我 学习类的概念 学习类的概念 我 用类重构代码 用类重构代码 我 顿悟时刻 顿悟时刻 Day 11 面向对象学习历程
Day 11 上午,我写了一个学生管理程序,用函数实现:
cangjie
var studentNames = ["张三", "李四", "王五"]
var studentAges = [20, 21, 19]
var studentScores = [95, 87, 92]
func printStudent(index: Int64) {
println("${studentNames[index]}, ${studentAges[index]}岁, ${studentScores[index]}分")
}
这个代码的问题分析
| 问题 | 描述 | 影响 | 严重程度 |
|---|---|---|---|
| 数据分散 | 三个数组分别存储 | 难以管理,容易遗漏 | ⭐⭐⭐⭐ |
| 同步困难 | 三个数组要保持一致 | 容易出现索引错位 | ⭐⭐⭐⭐⭐ |
| 扩展困难 | 添加字段要改多处 | 维护成本高 | ⭐⭐⭐⭐ |
| 可读性差 | 数据关系不明确 | 理解困难 | ⭐⭐⭐ |
Day 11 下午,我学会了类,代码清晰多了:
cangjie
class Student {
var name: String
var age: Int64
var score: Int64
func print() {
println("${name}, ${age}岁, ${score}分")
}
}
let students = [
Student("张三", 20, 95),
Student("李四", 21, 87),
Student("王五", 19, 92)
]
这个对比让我理解了面向对象的价值:把相关的数据和操作封装在一起,代码更清晰、更易维护。
什么时候用类?
- 数据和操作相关时(如学生的信息和操作)
- 需要创建多个相似对象时(如多个学生)
- 需要继承和多态时(如动物类的不同子类)
5.1、类与对象基础
类和对象的关系,类是模板,对象是实例。就像:
- 类是"学生"这个概念
- 对象是具体的"张三"、"李四"
类的组成:
- 属性(数据):描述对象的特征
- 方法(操作):描述对象的行为
- 构造函数:创建对象时的初始化逻辑
cangjie
// 定义类
class Person {
// 属性
var name: String
var age: Int64
// 构造函数
init(name: String, age: Int64) {
this.name = name
this.age = age
}
// 方法
func introduce(): Unit {
println("我叫${name},今年${age}岁")
}
func haveBirthday(): Unit {
age += 1
println("${name}过生日了,现在${age}岁")
}
}
main() {
// 创建对象
let person1 = Person("张三", 25)
let person2 = Person("李四", 30)
// 调用方法
person1.introduce()
person2.introduce()
person1.haveBirthday()
}
5.2、继承与多态
cangjie
// 基类
class Animal {
var name: String
init(name: String) {
this.name = name
}
func makeSound(): Unit {
println("${name}发出声音")
}
}
// 派生类
class Dog <: Animal {
var breed: String
init(name: String, breed: String) {
super.init(name)
this.breed = breed
}
// 重写方法
override func makeSound(): Unit {
println("${name}(${breed})汪汪叫")
}
func fetch(): Unit {
println("${name}去捡球")
}
}
class Cat <: Animal {
init(name: String) {
super.init(name)
}
override func makeSound(): Unit {
println("${name}喵喵叫")
}
}
main() {
let dog = Dog("旺财", "金毛")
let cat = Cat("咪咪")
dog.makeSound()
dog.fetch()
cat.makeSound()
}
5.3、接口与抽象
cangjie
// 定义接口
interface Drawable {
func draw(): Unit
}
interface Movable {
func move(x: Int64, y: Int64): Unit
}
// 实现接口
class Circle <: Drawable, Movable {
var x: Int64
var y: Int64
var radius: Int64
init(x: Int64, y: Int64, radius: Int64) {
this.x = x
this.y = y
this.radius = radius
}
func draw(): Unit {
println("在(${x}, ${y})绘制半径为${radius}的圆")
}
func move(newX: Int64, newY: Int64): Unit {
x = newX
y = newY
println("圆移动到(${x}, ${y})")
}
}
main() {
let circle = Circle(10, 20, 5)
circle.draw()
circle.move(30, 40)
circle.draw()
}
六、可空类型与错误处理(3 分钟)
6.1、可空类型与空安全
cangjie
main() {
// 可空类型声明
let name: String? = getUserName() // 可能为空
// 安全调用
if (let actualName = name) {
println("用户名: ${actualName}")
} else {
println("用户名为空")
}
// 空值合并运算符
let displayName = name ?? "访客"
println("显示名称: ${displayName}")
// 链式调用
let length = name?.length ?? 0
println("名称长度: ${length}")
}
func getUserName(): String? {
// 模拟可能返回空值的函数
let random = Math.random()
if (random > 0.5) {
return Some("张三")
} else {
return None
}
}
6.2、Result 类型错误处理
cangjie
// Result 类型用于错误处理
enum Result<T, E> {
| Success(T)
| Failure(E)
}
func divide(a: Int64, b: Int64): Result<Int64, String> {
if (b == 0) {
return Result.Failure("除数不能为零")
}
return Result.Success(a / b)
}
main() {
let result1 = divide(10, 2)
match (result1) {
case Success(value) => println("结果: ${value}")
case Failure(error) => println("错误: ${error}")
}
let result2 = divide(10, 0)
match (result2) {
case Success(value) => println("结果: ${value}")
case Failure(error) => println("错误: ${error}")
}
}
6.3、异常捕获与处理
cangjie
func readFile(path: String): String {
try {
// 尝试读取文件
let content = FileSystem.read(path)
return content
} catch (e: FileNotFoundException) {
println("文件不存在: ${e.message}")
return ""
} catch (e: IOException) {
println("IO错误: ${e.message}")
return ""
} finally {
println("清理资源")
}
}
main() {
let content = readFile("data.txt")
println("文件内容: ${content}")
}
七、实用示例(2 分钟)
实战项目的重要性(Day 20-25,11 月 23-28 日) ,学完基础语法后,我开始做实战项目。这是学习过程中最重要的阶段,也是最有成就感的阶段。为什么要做实战项目?
- 巩固知识:理论和实践结合,记得更牢
- 发现问题:实战中会遇到各种问题,解决问题的过程就是学习
- 建立信心:完成一个项目,会有很大的成就感
- 积累经验:实战经验比理论知识更有价值
我的实战经历 :
Day 20-21:做了一个计算器程序,学会了函数和错误处理
Day 22-23:做了一个学生成绩管理系统,学会了类和数据结构
Day 24-25:做了一个待办事项列表,学会了枚举和状态管理
这三个项目让我对仓颉有了全面的理解,也让我有信心开发更复杂的应用。
项目选择建议:
- 从简单开始:计算器、猜数字游戏
- 逐步提升:学生管理、图书管理
- 挑战自己:天气应用、聊天程序
7.1、简易计算器实现
项目背景:计算器是一个经典的入门项目。它涉及函数、条件判断、错误处理等核心概念,非常适合练习。
功能需求:
- 支持加减乘除四则运算
- 处理除零错误
- 返回计算结果或错误信息
设计思路:
- 定义一个 calculator 函数,接受两个数和一个运算符
- 使用 match 模式匹配不同的运算符
- 使用可空类型处理错误情况
实现要点:
- 使用 Float64 支持小数运算
- 使用可空类型(Float64?)表示可能失败的结果
- 除法要检查除数是否为零
cangjie
func calculator(a: Float64, b: Float64, operator: String): Float64? {
match (operator) {
case "+" => Some(a + b)
case "-" => Some(a - b)
case "*" => Some(a * b)
case "/" => {
if (b != 0.0) {
Some(a / b)
} else {
None
}
}
case _ => None
}
}
main() {
println("=== 简易计算器 ===")
let operations = [(10.0, 5.0, "+"), (10.0, 5.0, "-"),
(10.0, 5.0, "*"), (10.0, 5.0, "/"),
(10.0, 0.0, "/")]
for ((a, b, op) in operations) {
if (let result = calculator(a, b, op)) {
println("${a} ${op} ${b} = ${result}")
} else {
println("${a} ${op} ${b} = 错误")
}
}
}
7.2、学生成绩管理系统
cangjie
class Student {
var name: String
var scores: HashMap<String, Int64>
init(name: String) {
this.name = name
this.scores = HashMap()
}
func addScore(subject: String, score: Int64): Unit {
scores[subject] = score
}
func getAverage(): Float64 {
if (scores.size == 0) {
return 0.0
}
var total: Int64 = 0
for ((_, score) in scores) {
total += score
}
return Float64(total) / Float64(scores.size)
}
func printReport(): Unit {
println("=== ${name}的成绩单 ===")
for ((subject, score) in scores) {
println("${subject}: ${score}分")
}
println("平均分: ${getAverage()}")
}
}
main() {
let student = Student("张三")
student.addScore("语文", 95)
student.addScore("数学", 88)
student.addScore("英语", 92)
student.addScore("物理", 85)
student.printReport()
}
7.3、待办事项管理应用
cangjie
enum TaskStatus {
| Pending
| InProgress
| Completed
func toString(): String {
match (this) {
case Pending => "待办"
case InProgress => "进行中"
case Completed => "已完成"
}
}
}
class Task {
var id: Int64
var title: String
var status: TaskStatus
init(id: Int64, title: String) {
this.id = id
this.title = title
this.status = TaskStatus.Pending
}
func start(): Unit {
status = TaskStatus.InProgress
}
func complete(): Unit {
status = TaskStatus.Completed
}
}
class TodoList {
var tasks: ArrayList<Task>
var nextId: Int64
init() {
this.tasks = ArrayList()
this.nextId = 1
}
func addTask(title: String): Unit {
let task = Task(nextId, title)
tasks.append(task)
nextId += 1
println("已添加任务: ${title}")
}
func startTask(id: Int64): Unit {
for (task in tasks) {
if (task.id == id) {
task.start()
println("任务 ${id} 开始执行")
return
}
}
println("未找到任务 ${id}")
}
func completeTask(id: Int64): Unit {
for (task in tasks) {
if (task.id == id) {
task.complete()
println("任务 ${id} 已完成")
return
}
}
println("未找到任务 ${id}")
}
func listTasks(): Unit {
println("=== 待办事项列表 ===")
for (task in tasks) {
println("[${task.id}] ${task.title} - ${task.status.toString()}")
}
}
}
main() {
let todoList = TodoList()
todoList.addTask("学习仓颉语言")
todoList.addTask("开发鸿蒙应用")
todoList.addTask("写技术文章")
todoList.listTasks()
println("\n开始执行任务...")
todoList.startTask(1)
todoList.completeTask(1)
println()
todoList.listTasks()
}
八、常见问题与技巧
8.1、字符串操作技巧
cangjie
main() {
let text = "Hello, Cangjie!"
// 字符串长度
println("长度: ${text.length}")
// 字符串拼接
let greeting = "你好" + "," + "世界"
println(greeting)
// 字符串插值
let name = "张三"
let age = 25
println("${name}今年${age}岁")
// 字符串方法
println("大写: ${text.toUpperCase()}")
println("小写: ${text.toLowerCase()}")
println("包含: ${text.contains("Cangjie")}")
println("开头: ${text.startsWith("Hello")}")
println("结尾: ${text.endsWith("!")}")
// 字符串分割
let parts = text.split(", ")
for (part in parts) {
println("部分: ${part}")
}
// 字符串替换
let replaced = text.replace("Cangjie", "World")
println("替换后: ${replaced}")
}
8.2、数组高级操作
cangjie
main() {
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// map: 转换每个元素
let squared = numbers.map({ x => x * x })
println("平方: ${squared}")
// filter: 过滤元素
let evens = numbers.filter({ x => x % 2 == 0 })
println("偶数: ${evens}")
// reduce: 归约
let sum = numbers.reduce(0, { acc, x => acc + x })
println("总和: ${sum}")
// any: 是否存在满足条件的元素
let hasLarge = numbers.any({ x => x > 5 })
println("有大于5的数: ${hasLarge}")
// all: 是否所有元素都满足条件
let allPositive = numbers.all({ x => x > 0 })
println("都是正数: ${allPositive}")
// find: 查找第一个满足条件的元素
if (let found = numbers.find({ x => x > 5 })) {
println("第一个大于5的数: ${found}")
}
// 链式调用
let result = numbers
.filter({ x => x % 2 == 0 })
.map({ x => x * x })
.reduce(0, { acc, x => acc + x })
println("偶数平方和: ${result}")
}
8.3、类型别名与泛型
cangjie
// 定义类型别名
type UserId = Int64
type UserName = String
type Score = Int64
class User {
var id: UserId
var name: UserName
var score: Score
init(id: UserId, name: UserName, score: Score) {
this.id = id
this.name = name
this.score = score
}
}
main() {
let user = User(1001, "张三", 95)
println("用户 ${user.name} (ID: ${user.id}) 得分: ${user.score}")
}
九、学习路线建议
我的 30 天学习计划(Day 26-30,11 月 29-12 月 3 日)
2024-11-05 2024-11-07 2024-11-09 2024-11-11 2024-11-13 2024-11-15 2024-11-17 2024-11-19 2024-11-21 2024-11-23 2024-11-25 2024-11-27 2024-11-29 2024-12-01 2024-12-03 环境搭建 基础语法 函数与数据结构 面向对象 进阶特性 深入学习 标准库学习 并发编程 小型项目 中型项目 完整项目 基础阶段 进阶阶段 实战阶段 30天学习路线图
在帮助 15 位朋友学习仓颉的过程中,我总结出了一套高效的学习路线。这个路线经过实践验证,80% 的人都能在 30 天内从零基础到独立开发。学习的三个阶段:
基础阶段
第1-10天 进阶阶段
第11-20天 实战阶段
第21-30天 掌握语法 写简单程序 理解原理 解决问题 独立开发 完成项目
三个阶段对比
| 阶段 | 时间 | 目标 | 学习重点 | 学习方法 | 成果 |
|---|---|---|---|---|---|
| 基础阶段 | 第 1-10 天 | 掌握语法 | 变量、函数、类 | 多练习,不求甚解 | 能写简单程序 |
| 进阶阶段 | 第 11-20 天 | 理解原理 | 内存、并发、优化 | 多思考,理解原理 | 能解决问题 |
| 实战阶段 | 第 21-30 天 | 独立开发 | 项目实战 | 多实践,解决问题 | 能做完整项目 |
33% 33% 34% 30天学习时间分配 基础语法 进阶学习 实战项目
每个阶段的重点不同:
- 基础阶段:多练习,不求甚解
- 进阶阶段:多思考,理解原理
- 实战阶段:多实践,解决问题
9.1、初学者学习路线
第 1-3 天:基础语法(Day 1-3),这三天是最关键的,也是最容易放弃的。很多人觉得语法枯燥,看了就忘。我的建议是:
否 是 否 是 学习语法点 立即写代码 理解了? 写更多例子 记录笔记 第二天复习 记住了? 下一个语法点
学习建议
| 建议 | 说明 | 效果 |
|---|---|---|
| 每天 2-3 个语法点 | 不贪多,求精通 | ⭐⭐⭐⭐⭐ |
| 立即写代码验证 | 实践出真知 | ⭐⭐⭐⭐⭐ |
| 多写例子 | 加深理解 | ⭐⭐⭐⭐ |
| 第二天复习 | 巩固记忆 | ⭐⭐⭐⭐⭐ |
- 每天学习 2-3 个语法点,不贪多
- 每个语法点都要写代码验证
- 不理解的地方,多写几个例子
- 第二天复习前一天的内容
学习内容:
- Day 1:变量、数据类型、运算符
- Day 2:控制流(if、match)
- Day 3:循环(for、while)
学习方法:
- 看一个语法点,立即写代码
- 不要死记硬背,要理解原理
- 遇到问题,先自己思考,再查文档
第 4-5 天:函数和数据结构(Day 4-5),函数是编程的核心,一定要掌握好。数据结构是存储数据的方式,也很重要。
学习内容:
- Day 4:函数定义、参数、返回值、Lambda 表达式
- Day 5:数组、ArrayList、HashMap
学习重点:
- 理解函数的作用:代码复用
- 掌握数据结构的选择:什么时候用数组,什么时候用 HashMap
- 练习高阶函数:map、filter、reduce
第 6-7 天:面向对象(Day 6-7),面向对象是编程思想的转变,从面向过程到面向对象。这个转变需要时间,不要着急。
学习内容:
- Day 6:类和对象、属性和方法
- Day 7:继承、多态、接口
学习难点:
- 理解类和对象的关系
- 理解继承的作用
- 理解多态的意义
第 8-10 天:进阶特性(Day 8-10),进阶特性是仓颉的亮点,也是区别于其他语言的地方。
学习内容:
- Day 8:可空类型、空安全
- Day 9:错误处理、Result 类型
- Day 10:泛型基础
学习建议:
- 可空类型是仓颉的特色,一定要掌握
- 错误处理要用 Result 类型,不要用异常
- 泛型可以先了解,不需要深入
第 11-14 天:实战练习(Day 11-14)
实战练习 Day 11-12
计算器 Day 13
学生管理 Day 14
待办列表 函数练习 错误处理 用户输入 类的使用 数据结构 CRUD操作 枚举类型 状态管理 列表操作
实战是检验学习成果的最好方式。通过做项目,可以发现自己的不足,也可以巩固知识。
项目建议:
| 天数 | 项目 | 难度 | 练习重点 | 预计时间 |
|---|---|---|---|---|
| Day 11-12 | 计算器程序 | ⭐⭐⭐ | 函数、错误处理 | 4-6 小时 |
| Day 13 | 学生成绩管理 | ⭐⭐⭐⭐ | 类、数据结构 | 3-4 小时 |
| Day 14 | 待办事项列表 | ⭐⭐⭐⭐ | 枚举、状态管理 | 3-4 小时 |
实战开发流程
是 否 需求分析 设计方案 编写代码 测试验证 有问题? 调试修复 代码优化 完成项目
实战技巧:
- 先设计后编码:想清楚要做什么,再开始写代码
- 遇到问题先思考:不要一遇到问题就查答案
- 完成后优化:先实现功能,再优化代码
9.2、进阶开发路线
第 15-20 天:深入学习(Day 15-20)
深入学习阶段 标准库源码 内存管理 并发编程 性能优化 ArrayList实现 HashMap实现 String实现 所有权机制 借用规则 生命周期 协程基础 async/await 并发安全 性能分析 内存优化 算法优化
这个阶段要深入理解仓颉的核心特性,不仅要知道怎么用,还要知道为什么这样设计。
学习内容与时间分配
| 天数 | 主题 | 学习内容 | 学习方法 | 时间投入 |
|---|---|---|---|---|
| Day 15-16 | 标准库源码 | ArrayList、HashMap | 阅读源码、写笔记 | 4 小时/天 |
| Day 17-18 | 内存管理 | 所有权、借用 | 实验验证、画图理解 | 3 小时/天 |
| Day 19 | 并发编程 | 协程、async/await | 写并发程序 | 4 小时 |
| Day 20 | 性能优化 | 分析工具、优化技巧 | 性能测试 | 4 小时 |
学习方法:
- 阅读官方文档,理解设计理念
- 阅读标准库源码,学习最佳实践
- 做性能测试,理解优化原理
第 21-30 天:实战项目(Day 21-30)
2024-11-24 2024-11-25 2024-11-26 2024-11-27 2024-11-28 2024-11-29 2024-11-30 2024-12-01 2024-12-02 2024-12-03 2024-12-04 2024-12-05 确定项目方向 需求分析 架构设计 核心功能开发 UI开发 测试优化 文档编写 项目选择 天气应用 总结 实战项目时间规划
这个阶段要做一个完整的项目,从需求分析到架构设计,从编码实现到测试部署。
项目建议:
项目选择 天气应用 笔记应用 聊天应用 网络请求 UI开发 数据缓存 数据持久化 分布式同步 富文本编辑 并发编程 实时通信 消息队列
| 项目 | 难度 | 技术栈 | 开发时间 | 适合人群 |
|---|---|---|---|---|
| 天气应用 | ⭐⭐⭐ | 网络、UI、缓存 | 7-9 天 | 初学者 |
| 笔记应用 | ⭐⭐⭐⭐ | 持久化、同步 | 8-10 天 | 有基础 |
| 聊天应用 | ⭐⭐⭐⭐⭐ | 并发、实时通信 | 9-10 天 | 进阶者 |
项目要求:
- 功能完整:核心功能都要实现
- 代码规范:遵循最佳实践
- 有测试:至少有单元测试
- 有文档:README 要写清楚
9.3、学习资源推荐
官方资源(必看):
| 资源 | 类型 | 重要性 | 更新频率 | 链接 |
|---|---|---|---|---|
| 仓颉语言官方文档 | 文档 | ⭐⭐⭐⭐⭐ | 每周 | 最权威的学习资料 |
| HarmonyOS 开发者社区 | 社区 | ⭐⭐⭐⭐⭐ | 每天 | 有很多实战案例 |
| DevEco Studio 教程 | 教程 | ⭐⭐⭐⭐ | 每月 | 学习 IDE 的使用 |
实践项目(必做):
实践项目 初级 中级 高级 命令行工具
基础语法 计算器
函数使用 数据处理
数据结构 GUI应用
UI开发 鸿蒙应用
分布式能力 完整项目
综合实战
- 命令行工具:练习基础语法
- 数据处理程序:练习数据结构和算法
- GUI 应用:练习 UI 开发
- 鸿蒙原生应用:练习分布式能力
社区资源(推荐):
- GitHub 开源项目:学习优秀代码
- 技术博客和文章:了解最新动态
- 开发者论坛:交流学习心得
我的学习建议:
学习建议 文档 项目 社区 实践 反复阅读
每次新收获 多读代码
学习风格 积极参与
加深理解 理论结合
实践为主
- 官方文档要反复看,每次都有新收获
- 开源项目要多读,学习别人的代码风格
- 社区要多参与,交流能加深理解
- 实践最重要,理论要结合实践
十、快速参考卡片
说明:以下是仓颉语言的快速参考,方便查阅常用语法和 API。建议收藏本节,在实际开发中随时查看。
10.1、语法快速参考
基础语法:
- 变量:
let(不可变)、var(可变) - 函数:
func name(params): ReturnType { } - 类:
class Name { },接口:interface Name { } - 枚举:
enum Name { | Case1 | Case2 } - 可空类型:
Type?,安全解包:if (let v = value) { }
控制流:
- 条件:
if (condition) { } else { } - 模式匹配:
match (value) { case x => } - 循环:
for (i in 0..10) { }、while (condition) { }
数据结构:
- 数组:
[1, 2, 3] - 动态数组:
ArrayList<T>() - 哈希表:
HashMap<K, V>()
函数式编程:
- Lambda:
{ x: Int64 => x * x } - 高阶函数:
map、filter、reduce
10.2、常用 API 参考
字符串操作:
- 长度:
text.length - 大小写:
toUpperCase()、toLowerCase() - 查找:
contains("sub")、startsWith()、endsWith() - 分割:
split(",") - 替换:
replace("old", "new")
数组操作:
- 大小:
arr.size - 转换:
map({ x => x * 2 }) - 过滤:
filter({ x => x > 0 }) - 归约:
reduce(0, { acc, x => acc + x }) - 判断:
any({ x => x > 5 })、all({ x => x > 0 })
ArrayList 操作:
- 添加:
append(item)、insert(index, item) - 删除:
remove(index)、clear() - 访问:
[index]、size
HashMap 操作:
- 设置:
map[key] = value - 获取:
map.get(key) - 判断:
containsKey(key) - 删除:
remove(key)、clear()
提示:完整的 API 文档请参考官方文档,这里只列出最常用的方法。
十一、关于作者与学习资源
11.1、作者简介
郭靖,笔名"白鹿第一帅",大数据与大模型开发工程师,中国开发者影响力年度榜单人物。在编程语言教学和技术写作方面有丰富经验,擅长将复杂的技术概念用简洁易懂的方式呈现,帮助初学者快速上手新技术,已帮助数百名开发者成功转型。作为技术内容创作者,自 2015 年至今累计发布技术博客 300 余篇,全网粉丝超 60000+,获得 CSDN"博客专家"等多个技术社区认证,并成为互联网顶级技术公会"极星会"成员。
同时作为资深社区组织者,运营多个西南地区技术社区,包括 CSDN 成都站(10000+ 成员)、AWS User Group Chengdu、字节跳动 Trae Friends@Chengdu等,累计组织线下技术活动超 50 场,致力于推动技术交流与开发者成长。
CSDN 博客地址 :https://blog.csdn.net/qq_22695001
11.2、学习资源
- 仓颉语言官方教程
- DevEco Studio 下载
- 华为开发者学院
- Kotlin 语言参考(语法相似)
- Rust 程序设计语言(设计理念参考)
文章作者 :白鹿第一帅,作者主页 :https://blog.csdn.net/qq_22695001,未经授权,严禁转载,侵权必究!
总结
恭喜完成仓颉语言 30 天学习之旅!我们系统学习了变量声明、数据类型、控制流、函数、数据结构、面向对象、可空类型等核心语法,通过 30 多个代码示例和 3 个实用案例建立了对仓颉的整体认知。从我帮助 15 位朋友学习的经验看,掌握这些基础后就可以编写简单程序了,其中 80% 的人在学完后一周内就开发出了自己的第一个应用。学习建议:第一周巩固基础语法每天练习 2 小时,第二周学习类型系统和泛型深入理解编译期检查,第三周深入内存管理和并发编程掌握高性能开发技巧,第四周开始实战项目将所学知识融会贯通。学习编程最重要的是动手实践而不是死记硬背,建议完成文中所有示例代码并尝试扩展功能,遇到问题多查文档多思考。仓颉简洁而强大,特别适合鸿蒙原生应用开发,持续学习和实践你很快就能成为仓颉开发高手。

我是白鹿,一个不懈奋斗的程序猿。望本文能对你有所裨益,欢迎大家的一键三连!若有其他问题、建议或者补充可以留言在文章下方,感谢大家的支持!