
本课目标· 完成仓颉 SDK 的下载、解压与环境变量配置。· 能使用 cjc 和 cjpm 验证安装是否成功。· 掌握仓颉程序入口 main 的写法。· 掌握变量 let 与 var 的区别。· 认识基础类型Int64、Float64、Bool、String、Unit。· 掌握函数 func、命名参数和默认值。· 掌握分支 if、循环 while、for-in。· 理解区间 … 与 … 的区别。· 掌握字符串插值 ${表达式}。· 能独立完成本课的选择题、判断题、填空题、改错题、输出预测题和编程题。一、安装与环境变量配置下载 SDK# 打开仓颉语言官网或华为开发者联盟找到仓颉 SDK 下载页# 选择对应平台Windows、Linux 或 macOS# 下载后解压到无中文、无空格的目录# Windows 示例目录C:\Cangjie# Linux/macOS 示例目录$HOME/cangjieWindows 环境变量配置CANGJIE_HOME C:\Cangjie # 设置仓颉根目录 Path 追加%CANGJIE_HOME%\bin # 将 bin 目录加入 Path使 cjc 可全局使用配置完成后需要打开新的命令行窗口环境变量才会生效。Linux / macOS 环境变量配置exportCANGJIE_HOME$HOME/cangjie# 设置仓颉根目录exportPATH$CANGJIE_HOME/bin:$PATH# 将 bin 目录加入 PATHexportLD_LIBRARY_PATH$CANGJIE_HOME/lib:$LD_LIBRARY_PATH# Linux 动态库路径exportDYLD_LIBRARY_PATH$CANGJIE_HOME/lib:$DYLD_LIBRARY_PATH# macOS 动态库路径source~/.bashrc# 如果使用 bash使配置立即生效source~/.zshrc# 如果使用 zsh使配置立即生效验证安装cjc--version# 查看仓颉编译器版本成功会输出版本号cjpm--version# 查看仓颉包管理工具版本成功会输出版本号编译与运行第一个程序cjc hello.cj-ohello# 编译 hello.cj生成可执行文件 hello./hello# 运行程序Linux/macOS 使用 ./Windows 下cjc hello.cj-ohello.exe# 编译生成 hello.exehello.exe# 运行程序二、核心语法知识点与逐行注释示例第一个仓颉程序// hello.cj // 文件名扩展名为 .cj main(): Int64 { // 程序入口返回 Int64 类型 println(Hello, Cangjie!) // 输出一行文本自动换行 return 0 // 返回 0表示程序正常退出 } // main 函数结束main 无返回值main() { // 程序入口无返回值 println(你好仓颉) // 输出一行文本 } // main 函数结束变量let 与 varmain() { // 程序入口 let name: String 仓颉 // 定义不可变变量 name类型 String var count: Int64 10 // 定义可变变量 count类型 Int64 count 20 // 修改 count合法 // name Java // 编译错误let 变量不可重新赋值 println(${name} 数量 ${count}) // 字符串插值输出变量值 } // main 函数结束基础类型main() { // 程序入口 let n: Int64 42 // 定义 64 位有符号整数 let f: Float64 3.14 // 定义 64 位浮点数 let ok: Bool true // 定义布尔值 let s: String hello // 定义字符串 println(${n}, ${f}, ${ok}, ${s}) // 输出所有变量 } // main 函数结束类型推断main() { // 程序入口 let score 95 // 初始值为整数推断为 Int64 let pi 3.14 // 初始值为小数推断为 Float64 println(${score}, ${pi}) // 输出两个变量 } // main 函数结束函数定义与调用func add(a: Int64, b: Int64): Int64 { // 定义函数 add返回 Int64 return a b // 返回两数之和 } // 函数结束 main() { // 程序入口 println(add(3, 5)) // 调用 add输出 8 } // main 函数结束命名参数func greet(name!: String): String { // 定义命名参数函数参数名后加 ! return 你好${name} // 返回问候语 } // 函数结束 main() { // 程序入口 println(greet(name: 小明)) // 调用时必须写参数名 name: } // main 函数结束命名参数带默认值func greet(name!: String, greeting!: String 你好): String { // greeting 有默认值 return ${greeting}${name} // 返回拼接结果 } // 函数结束 main() { // 程序入口 println(greet(name: 仓颉)) // 省略 greeting使用默认值 println(greet(name: 开发者, greeting: 欢迎)) // 显式传入 greeting } // main 函数结束if 分支main() { // 程序入口 let score 85 // 定义成绩推断为 Int64 if (score 90) { // 条件必须用圆括号 println(优秀) // 90 分及以上 } else if (score 60) { // 否则继续判断是否及格 println(及格) // 60 分及以上 } else { // 以上都不成立 println(不及格) // 低于 60 分 } // if 结束 } // main 函数结束while 循环main() { // 程序入口 var i 1 // 定义循环变量 i while (i 3) { // 当 i 3 时循环 println(while: ${i}) // 输出当前 i i i 1 // i 自增 } // while 结束 } // main 函数结束for-in 循环main() { // 程序入口 for (j in 1..3) { // 遍历闭区间 1 到 3 println(for: ${j}) // 输出当前 j } // for 结束 } // main 函数结束区间 … 与 …main() { // 程序入口 for (i in 1..5) { // 左闭右开1、2、3、4 println(左闭右开${i}) // 输出当前 i } // for 结束 for (i in 1..5) { // 闭区间1、2、3、4、5 println(闭区间${i}) // 输出当前 i } // for 结束 } // main 函数结束字符串插值main() { // 程序入口 let a 10 // 定义变量 a let b 20 // 定义变量 b println(a b ${a b}) // 在字符串中嵌入表达式结果 } // main 函数结束注释// 这是单行注释 // 从 // 到行尾都是注释 /* * 这是多行注释 // 多行注释开始 * 可以写多行内容 // 中间内容 */ // 多行注释结束 main() { // 程序入口 println(注释演示) // 输出文本 } // main 函数结束三、多元化习题、答案与解读A. 选择题题目1仓颉程序的入口是A. func main()B. main()C. start()D. init()答案与解读B。main 是仓颉约定的程序入口顶层定义不需要 func。题目2下列哪个关键字定义可变变量A. letB. varC. constD. final答案与解读B。var 定义可变变量let 定义不可变变量。题目3仓颉字符串插值的正确写法是A. “你好, $name”B. “你好, {name}”C. “你好, ${name}”D. “你好, #name”答案与解读C。仓颉使用 ${表达式} 进行字符串插值。题目4仓颉的 if 条件必须用什么包裹A. 方括号B. 圆括号C. 花括号D. 不需要答案与解读B。if 条件必须用圆括号例如 if (x 0) { }。题目51…5 表示哪些整数A. 1、2、3、4B. 1、2、3、4、5C. 1、3、5D. 5、4、3、2、1答案与解读B。… 是闭区间包含两端。题目6仓颉定义普通函数使用哪个关键字A. functionB. defC. funcD. fn答案与解读C。仓颉用 func 定义普通函数。题目7命名参数在定义时参数名后应加什么符号A. ?B. !C. D. #答案与解读B。定义命名参数时参数名后加 !调用时必须写参数名。题目8仓颉合法整数类型是A. intB. IntegerC. Int64D. number答案与解读C。Int64 是仓颉整数类型之一。B. 判断题题目1仓颉源文件扩展名是 .cj。答案与解读正确。仓颉源文件使用 .cj 后缀。题目2let 变量初始化后可以再次赋值。答案与解读错误。let 不可变重新赋值需使用 var。题目3main 函数必须用 func 关键字定义。答案与解读错误。main 是特殊入口不需要 func。题目4if 条件可以省略圆括号。答案与解读错误。if 条件必须用圆括号。题目5println 输出内容后会自动换行。答案与解读正确。println 输出后换行print 不换行。题目6仓颉是静态强类型语言。答案与解读正确。仓颉是静态强类型语言。题目7字符串中 ${} 可以嵌入表达式。答案与解读正确。${} 内可写变量或表达式。题目8Unit 表示无值类似其他语言的 void。答案与解读正确。Unit 表示无值。题目9变量类型标注不可省略。答案与解读错误。有初始值时通常可推断类型可省略标注。题目10for (i in 1…5) 会遍历 1 到 5。答案与解读错误。1…5 是左闭右开遍历 1 到 41…5 才遍历 1 到 5。C. 填空题题目1仓颉程序入口是 ______ 函数。答案与解读main。题目2定义不可变变量用 ______可变变量用 ______。答案与解读let、var。题目3仓颉定义普通函数使用 ______ 关键字。答案与解读func。题目4字符串插值语法是 ______。答案与解读${表达式}。题目5条件分支关键字是 ______。答案与解读if。题目6遍历 1 到 10 的 for-in 写法for (i in ______) { … }。答案与解读1…10。题目7输出一行内容使用 ______。答案与解读println。题目8仓颉布尔类型是 ______值有 ______ 和 ______。答案与解读Bool、true、false。题目9函数无返回值时返回类型可写为 ______。答案与解读Unit。题目10命名参数在定义时参数名后加 ______。答案与解读!。D. 代码改错题题目1main() { // 程序入口 let a 10 // 定义不可变变量 a a 20 // 错误let 不能重新赋值 println(a) // 输出 a } // main 结束答案与解读main() { // 程序入口 var a 10 // 将 let 改为 var允许重新赋值 a 20 // 修改 a 的值 println(a) // 输出 a } // main 结束let 不可重新赋值需要改为 var。题目2main() { // 程序入口 if x 0 { // 错误条件缺少圆括号x 未定义 println(正数) // 输出“正数” } // if 结束 } // main 结束答案与解读main() { // 程序入口 let x 1 // 补充定义变量 x if (x 0) { // 条件必须加圆括号 println(正数) // 输出“正数” } // if 结束 } // main 结束if 条件必须用圆括号原代码中 x 也未定义。题目3func add(a: Int64, b: Int64) { // 错误缺少返回类型 return a b // 返回 a b } // 函数结束答案与解读func add(a: Int64, b: Int64): Int64 { // 补充返回类型 Int64 return a b // 返回两数之和 } // 函数结束有 return 返回值时应声明返回类型 : Int64。题目4main() { // 程序入口 for (i in 1..5) { // 左闭右开只遍历 1 到 4 println(i) // 输出 i } // for 结束 } // main 结束要求输出 1 2 3 4 5如何修改答案与解读main() { // 程序入口 for (i in 1..5) { // 改为闭区间遍历 1 到 5 println(i) // 输出 i } // for 结束 } // main 结束… 左闭右开… 才是包含右端点。题目5func greet(name!: String) { // 定义命名参数函数 println(你好${name}) // 输出问候语 } // 函数结束 main() { // 程序入口 greet(小明) // 错误命名参数必须写参数名 } // main 结束答案与解读func greet(name!: String) { // 定义命名参数函数 println(你好${name}) // 输出问候语 } // 函数结束 main() { // 程序入口 greet(name: 小明) // 命名参数调用时必须写参数名 } // main 结束命名参数调用时必须写参数名 name:。E. 输出预测题题目1main() { // 程序入口 let a 5 // a 5 var b 3 // b 3 b b a // b 更新为 8 println(${a} ${b} ${a b}) // 输出 5 8 13 } // main 结束答案与解读输出 5 8 13。a 5b 3 5 8a b 13。题目2main() { // 程序入口 var sum 0 // 累加器初始为 0 for (i in 1..5) { // 遍历 1、2、3、4、5 sum sum i // 将 i 累加到 sum } // for 结束 println(sum) // 输出 15 } // main 结束答案与解读输出 15。1 2 3 4 5 15。题目3func isEven(n: Int64): Bool { // 定义判断偶数的函数 return n % 2 0 // 余数为 0 返回 true } // 函数结束 main() { // 程序入口 let x 7 // 定义变量 x if (isEven(x)) { // 调用 isEven 判断 println(偶数) // 条件为 true 输出“偶数” } else { // 否则 println(奇数) // 输出“奇数” } // if 结束 } // main 结束答案与解读输出 奇数。7 % 2 1isEven(7) 返回 false进入 else。题目4main() { // 程序入口 var i 3 // i 初始为 3 while (i 0) { // 当 i 大于 0 时循环 println(i) // 输出当前 i i i - 1 // i 递减 } // while 结束 } // main 结束答案与解读输出3 2 1while 循环i 从 3 递减到 1。题目5func makeMsg(name!: String, greeting!: String 你好): String { // 命名参数greeting 有默认值 return ${greeting}${name} // 返回拼接后的消息 } // 函数结束 main() { // 程序入口 println(makeMsg(name: 仓颉)) // 使用默认 greeting println(makeMsg(name: 开发者, greeting: 欢迎)) // 显式传入 greeting } // main 结束答案与解读输出你好仓颉 欢迎开发者greeting 有默认值第一次调用省略第二次显式传入。F. 编程题题目1定义两个 Int64 变量输出它们的和、差、积、商。答案与解读main() { // 程序入口 let a: Int64 20 // 定义整数 a let b: Int64 6 // 定义整数 b println(和${a b}) // 输出和26 println(差${a - b}) // 输出差14 println(积${a * b}) // 输出积120 println(商${a / b}) // 输出整数商3 } // main 结束整数除法会截断小数部分20 / 6 结果为 3。题目2编写函数 isPositive(n: Int64): Bool判断是否为正数。答案与解读func isPositive(n: Int64): Bool { // 定义判断正数的函数 return n 0 // 大于 0 返回 true否则返回 false } // 函数结束 main() { // 程序入口 println(isPositive(5)) // 输出 true println(isPositive(0)) // 输出 false println(isPositive(-3)) // 输出 false } // main 结束比较运算返回 Bool 类型。题目3用 for-in 计算 1 到 100 中所有偶数的和。答案与解读main() { // 程序入口 var sum 0 // 偶数和初始为 0 for (i in 1..100) { // 遍历 1 到 100 if (i % 2 0) { // 判断是否为偶数 sum sum i // 累加偶数 } // if 结束 } // for 结束 println(偶数和${sum}) // 输出 2550 } // main 结束输出 偶数和2550。偶数序列 24…100和为 2550。题目4编写函数 factorial(n: Int64): Int64用 while 计算阶乘。答案与解读func factorial(n: Int64): Int64 { // 定义阶乘函数 var result 1 // 结果初始为 1 var i 1 // 循环变量从 1 开始 while (i n) { // 当 i n 时循环 result result * i // 累乘 i i 1 // i 自增 } // while 结束 return result // 返回阶乘结果 } // 函数结束 main() { // 程序入口 println(factorial(5)) // 输出 120 } // main 结束5! 5 × 4 × 3 × 2 × 1 120。题目5编写函数 describeScore(score: Int64): String90 及以上返回“优秀”60 及以上返回“及格”否则返回“不及格”。答案与解读func describeScore(score: Int64): String { // 定义成绩描述函数 if (score 90) { // 90 分及以上 return 优秀 // 返回“优秀” } else if (score 60) { // 60 分及以上 return 及格 // 返回“及格” } else { // 低于 60 分 return 不及格 // 返回“不及格” } // if 结束 } // 函数结束 main() { // 程序入口 println(describeScore(95)) // 输出“优秀” println(describeScore(72)) // 输出“及格” println(describeScore(45)) // 输出“不及格” } // main 结束分段判断返回对应字符串。题目6使用命名参数和默认值定义 introduce(name!: String, age!: Int64 18, city!: String “北京”): String返回自我介绍。答案与解读func introduce(name!: String, age!: Int64 18, city!: String 北京): String { // 命名参数带默认值 return 我叫${name}今年${age}岁来自${city}。 // 返回自我介绍 } // 函数结束 main() { // 程序入口 println(introduce(name: 小明)) // 只传 name使用默认 age、city println(introduce(name: 小红, age: 20)) // 传 name、agecity 用默认 println(introduce(name: 小刚, age: 22, city: 上海)) // 全部传入 } // main 结束命名参数可选择性传参未传的使用默认值。G. 开放综合题题目1用自己的话解释为什么 main 函数不需要 func 关键字答案与解读main 是仓颉约定的程序入口编译器会特殊识别因此不需要像普通函数那样写 func。普通函数必须用 func 定义。题目2简述值类型与引用类型的区别并各举一个例子。答案与解读值类型赋值时复制值修改副本不影响原值例如 Int64、Bool、struct。引用类型赋值时复制引用多个变量可能指向同一对象例如 class、Array。本课只需建立初步概念。四、知识点总结· 程序入口main 函数顶层定义不需要 func。· 源文件扩展名 .cj。· 变量let 不可变var 可变类型可推断。· 基础类型Int64、Float64、Bool、String、Unit。· 函数用 func 定义参数写法为 名: 类型。· 命名参数定义时参数名后加 !调用时写参数名。· 默认值命名参数可设默认值。· 分支if (条件) { … } else { … }。· 循环while、for-in、do-while。· 区间… 左闭右开… 闭区间。· 字符串插值${表达式}。· 注释// 单行/* */ 多行。· 编译运行cjc hello.cj -o hello然后 ./hello。· 包管理cjpm 可用于初始化、构建、运行项目。五、易错点· let 和 var 别混需要修改就用 var否则用 let。· if 条件要括号写 if (x 0)不要写 if x 0。· 区间 … 与 … 不同1…5 是 1 到 41…5 是 1 到 5。· 命名参数调用要写名字定义 name!调用必须 name: 值。· 函数有返回值要写返回类型如 : Int64、: Bool、: String。· 字符串插值用 ${}不是 $name也不是 {name}。· 整数除法会截断5 / 2 结果是 2。· main 是特殊入口不需要 func但普通函数必须用 func。六、本课通关清单· 完成仓颉 SDK 下载、解压和环境变量配置。· 能用 cjc --version 验证安装。· 能写出并运行 main() 入口程序。· 能正确使用 let 和 var。· 能定义并调用普通函数、命名参数函数。· 能使用 if、while、for-in 控制流程。· 能使用 ${} 进行字符串插值。· 能区分 … 和 … 的区间含义。· 能独立完成本课全部习题。