【仓颉纪元】仓颉学习深度实践:30 天从零基础到独立开发

文章目录


前言

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 配置较低的电脑
适合场景 完整项目开发 快速脚本验证 -

最初我纠结于两个选择:

  1. 使用 DevEco Studio(图形化 IDE,功能强大)
  2. 使用命令行工具(轻量级,适合老手)

作为一个习惯用 VSCode 的开发者,我最初想用命令行工具。但尝试后发现,DevEco Studio 的代码提示、调试功能、项目管理都很完善,特别适合初学者。最终我选择了 DevEco Studio,这个决定让我后续的学习效率提升了很多。

给初学者的建议

  • 如果你是编程初学者,强烈推荐 DevEco Studio
  • 如果你有丰富的编程经验,可以尝试命令行工具
  • 两种方式可以并存,根据场景选择

1.1、开发工具选择与安装

方式一:使用 DevEco Studio(推荐初学者),DevEco Studio 是华为官方提供的集成开发环境,专为鸿蒙和仓颉开发设计。它提供了代码补全、语法高亮、调试工具、项目管理等功能,大大提升开发效率。

安装步骤:

  1. 访问华为开发者官网,下载 DevEco Studio
  2. 安装完成后,打开 IDE,在插件市场搜索"Cangjie"
  3. 安装仓颉插件,重启 IDE
  4. 创建新项目: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 没意义,但我认为它很重要:

  1. 验证环境搭建是否成功
  2. 熟悉编译和运行流程
  3. 建立信心,迈出第一步

我的第一次尝试 ,创建 main.cj 文件:

cangjie 复制代码
// 这是注释
main() {
    println("你好,仓颉!")
    println("Hello, Cangjie!")
}

代码说明

  • main():程序的入口函数,类似 Java 的 main 方法
  • println():打印函数,会自动换行
  • //:单行注释,编译器会忽略
  • 字符串用双引号包裹,支持中文

运行程序:

bash 复制代码
cjc run main.cj

输出:

复制代码
你好,仓颉!
Hello, Cangjie!

第一次运行的感受,当我看到输出时,虽然只是两行文字,但心里很有成就感。这说明环境搭建成功了,我可以开始真正的学习了。
cjc run 编译失败 修复错误 编译成功 成功! 编写代码 编译 检查错误 运行 查看输出 常见错误:

  • 语法错误
  • 拼写错误
  • 编码问题

常见问题

  1. 如果提示"cjc: command not found",说明环境变量没配置好
  2. 如果提示编译错误,检查代码是否有拼写错误
  3. 如果中文显示乱码,检查文件编码是否为 UTF-8

二、基础语法(10 分钟)

学习方法建议(Day 2-5,11 月 5-8 日),基础语法是学习的重点,也是最容易放弃的阶段。很多人觉得语法枯燥,看了就忘。我的经验是:不要死记硬背,要通过实践来学习。

我的学习方法
否 是 看语法点 写代码验证 理解了吗? 写更多例子 记录笔记 第二天复习 进入下一个

  1. 看一个语法点,立即写代码验证
  2. 不理解的地方,写多个例子尝试
  3. 每天学习 2-3 个语法点,不贪多
  4. 第二天复习前一天的内容

学习效果对比

学习方式 记忆效果 理解深度 时间投入 推荐度
只看不练 ⭐⭐ ⭐⭐ 1 小时/天
看完就练 ⭐⭐⭐⭐ ⭐⭐⭐⭐ 2 小时/天
大量练习 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 3 小时/天 ✅✅

这个方法让我在 4 天内掌握了基础语法,而且记得很牢。

2.1、变量声明与作用域

变量是什么?(Day 2 上午),变量就是存储数据的容器。学习变量时,我最初不理解 let 和 var 的区别,写了很多代码才明白:

  • let:声明不可变变量,一旦赋值就不能改变
  • var:声明可变变量,可以多次赋值

为什么要区分可变和不可变? 这是我学习仓颉时的第一个困惑。后来我理解了:

  1. 不可变变量更安全,不会被意外修改
  2. 不可变变量便于编译器优化
  3. 函数式编程推荐使用不可变变量

在实际开发中,我发现 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、函数定义与参数

函数的组成部分,一个完整的函数包含:

  1. 函数名:描述函数的功能
  2. 参数列表:函数需要的输入
  3. 返回类型:函数的输出类型
  4. 函数体:具体的实现逻辑

命名建议

规范 好的示例 不好的示例 说明
动词开头 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、类与对象基础

类和对象的关系,类是模板,对象是实例。就像:

  • 类是"学生"这个概念
  • 对象是具体的"张三"、"李四"

类的组成

  1. 属性(数据):描述对象的特征
  2. 方法(操作):描述对象的行为
  3. 构造函数:创建对象时的初始化逻辑
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 日) ,学完基础语法后,我开始做实战项目。这是学习过程中最重要的阶段,也是最有成就感的阶段。为什么要做实战项目?

  1. 巩固知识:理论和实践结合,记得更牢
  2. 发现问题:实战中会遇到各种问题,解决问题的过程就是学习
  3. 建立信心:完成一个项目,会有很大的成就感
  4. 积累经验:实战经验比理论知识更有价值

我的实战经历

Day 20-21:做了一个计算器程序,学会了函数和错误处理

Day 22-23:做了一个学生成绩管理系统,学会了类和数据结构

Day 24-25:做了一个待办事项列表,学会了枚举和状态管理

这三个项目让我对仓颉有了全面的理解,也让我有信心开发更复杂的应用。

项目选择建议

  1. 从简单开始:计算器、猜数字游戏
  2. 逐步提升:学生管理、图书管理
  3. 挑战自己:天气应用、聊天程序

7.1、简易计算器实现

项目背景:计算器是一个经典的入门项目。它涉及函数、条件判断、错误处理等核心概念,非常适合练习。

功能需求

  1. 支持加减乘除四则运算
  2. 处理除零错误
  3. 返回计算结果或错误信息

设计思路

  1. 定义一个 calculator 函数,接受两个数和一个运算符
  2. 使用 match 模式匹配不同的运算符
  3. 使用可空类型处理错误情况

实现要点

  • 使用 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 个语法点 不贪多,求精通 ⭐⭐⭐⭐⭐
立即写代码验证 实践出真知 ⭐⭐⭐⭐⭐
多写例子 加深理解 ⭐⭐⭐⭐
第二天复习 巩固记忆 ⭐⭐⭐⭐⭐
  1. 每天学习 2-3 个语法点,不贪多
  2. 每个语法点都要写代码验证
  3. 不理解的地方,多写几个例子
  4. 第二天复习前一天的内容

学习内容

  • 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 开源项目:学习优秀代码
  • 技术博客和文章:了解最新动态
  • 开发者论坛:交流学习心得

我的学习建议
学习建议 文档 项目 社区 实践 反复阅读
每次新收获 多读代码
学习风格 积极参与
加深理解 理论结合
实践为主

  1. 官方文档要反复看,每次都有新收获
  2. 开源项目要多读,学习别人的代码风格
  3. 社区要多参与,交流能加深理解
  4. 实践最重要,理论要结合实践

十、快速参考卡片

说明:以下是仓颉语言的快速参考,方便查阅常用语法和 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 }
  • 高阶函数:mapfilterreduce

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、学习资源


文章作者白鹿第一帅作者主页https://blog.csdn.net/qq_22695001,未经授权,严禁转载,侵权必究!


总结

恭喜完成仓颉语言 30 天学习之旅!我们系统学习了变量声明、数据类型、控制流、函数、数据结构、面向对象、可空类型等核心语法,通过 30 多个代码示例和 3 个实用案例建立了对仓颉的整体认知。从我帮助 15 位朋友学习的经验看,掌握这些基础后就可以编写简单程序了,其中 80% 的人在学完后一周内就开发出了自己的第一个应用。学习建议:第一周巩固基础语法每天练习 2 小时,第二周学习类型系统和泛型深入理解编译期检查,第三周深入内存管理和并发编程掌握高性能开发技巧,第四周开始实战项目将所学知识融会贯通。学习编程最重要的是动手实践而不是死记硬背,建议完成文中所有示例代码并尝试扩展功能,遇到问题多查文档多思考。仓颉简洁而强大,特别适合鸿蒙原生应用开发,持续学习和实践你很快就能成为仓颉开发高手。


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

相关推荐
白鹿第一帅5 天前
【成长纪实】HarmonyOS 场景技术共建实践|轻备份技术在《社区之星》应用中的深度应用
harmonyos·白鹿第一帅·csdn成都站·鸿蒙开放能力·鸿蒙学习之路·harmonyos创新赛·轻备份技术
自在极意功。5 天前
Java static关键字深度解析
java·开发语言·面向对象·static
白鹿第一帅7 天前
【案例实战】鸿蒙元服务开发实战:从云原生到移动端,包大小压缩 96% 启动提速 75% 的轻量化设计
harmonyos·白鹿第一帅·鸿蒙元服务·csdn成都站·鸿蒙开放能力·鸿蒙学习之路·鸿蒙元服务框架
白鹿第一帅7 天前
【参赛心得】鸿蒙三方库适配实战:从 Hadoop 生态到鸿蒙生态,企业级项目集成的 6 个最佳实践
harmonyos·白鹿第一帅·鸿蒙三方库·csdn成都站·鸿蒙开放能力·鸿蒙学习之路·harmonyos创新赛
白鹿第一帅8 天前
【成长纪实】星光不负 码向未来|我的 HarmonyOS 学习之路与社区成长故事
harmonyos·白鹿第一帅·成都ug社区·csdn成都站·鸿蒙开放能力·鸿蒙学习之路·鸿蒙第一课
Mintopia13 天前
🧩 TypeScript防御性编程:让Bug无处遁形的艺术
前端·typescript·函数式编程
桦说编程15 天前
CompletableFuture API 过于复杂?选取7个最常用的方法,解决95%的问题
java·后端·函数式编程
liulilittle19 天前
Y组合子剖析:C++ 中的递归魔法
开发语言·c++·编程语言·函数式编程·函数式·函数编程·y组合子
桦说编程20 天前
CompletableFuture 异常处理常见陷阱——非预期的同步异常
后端·性能优化·函数式编程