【仓颉语言基础语法学与练】第1课:从零开始

本课目标

· 完成仓颉 SDK 的下载、解压与环境变量配置。

· 能使用 cjc 和 cjpm 验证安装是否成功。

· 掌握仓颉程序入口 main 的写法。

· 掌握变量 let 与 var 的区别。

· 认识基础类型:Int64、Float64、Bool、String、Unit。

· 掌握函数 func、命名参数和默认值。

· 掌握分支 if、循环 while、for-in。

· 理解区间 ... 与 ...= 的区别。

· 掌握字符串插值 ${表达式}。

· 能独立完成本课的选择题、判断题、填空题、改错题、输出预测题和编程题。


一、安装与环境变量配置

  1. 下载 SDK
bash 复制代码
# 打开仓颉语言官网或华为开发者联盟,找到仓颉 SDK 下载页
# 选择对应平台:Windows、Linux 或 macOS
# 下载后解压到无中文、无空格的目录
# Windows 示例目录:C:\Cangjie
# Linux/macOS 示例目录:$HOME/cangjie
  1. Windows 环境变量配置
text 复制代码
CANGJIE_HOME = C:\Cangjie                    # 设置仓颉根目录
Path 追加:%CANGJIE_HOME%\bin                # 将 bin 目录加入 Path,使 cjc 可全局使用

配置完成后,需要打开新的命令行窗口,环境变量才会生效。

  1. Linux / macOS 环境变量配置
bash 复制代码
export CANGJIE_HOME=$HOME/cangjie                          # 设置仓颉根目录
export PATH=$CANGJIE_HOME/bin:$PATH                        # 将 bin 目录加入 PATH
export LD_LIBRARY_PATH=$CANGJIE_HOME/lib:$LD_LIBRARY_PATH  # Linux 动态库路径
export DYLD_LIBRARY_PATH=$CANGJIE_HOME/lib:$DYLD_LIBRARY_PATH # macOS 动态库路径

source ~/.bashrc    # 如果使用 bash,使配置立即生效
source ~/.zshrc     # 如果使用 zsh,使配置立即生效
  1. 验证安装
bash 复制代码
cjc --version    # 查看仓颉编译器版本,成功会输出版本号
cjpm --version   # 查看仓颉包管理工具版本,成功会输出版本号
  1. 编译与运行第一个程序
bash 复制代码
cjc hello.cj -o hello    # 编译 hello.cj,生成可执行文件 hello
./hello                  # 运行程序,Linux/macOS 使用 ./

Windows 下:

bash 复制代码
cjc hello.cj -o hello.exe    # 编译生成 hello.exe
hello.exe                    # 运行程序

二、核心语法知识点与逐行注释示例

  1. 第一个仓颉程序
cangjie 复制代码
// hello.cj                        // 文件名,扩展名为 .cj
main(): Int64 {                    // 程序入口,返回 Int64 类型
    println("Hello, Cangjie!")     // 输出一行文本,自动换行
    return 0                       // 返回 0,表示程序正常退出
}                                  // main 函数结束
  1. main 无返回值
cangjie 复制代码
main() {                           // 程序入口,无返回值
    println("你好,仓颉")          // 输出一行文本
}                                  // main 函数结束
  1. 变量:let 与 var
cangjie 复制代码
main() {                           // 程序入口
    let name: String = "仓颉"      // 定义不可变变量 name,类型 String
    var count: Int64 = 10          // 定义可变变量 count,类型 Int64

    count = 20                     // 修改 count,合法
    // name = "Java"               // 编译错误:let 变量不可重新赋值

    println("${name} 数量 ${count}") // 字符串插值,输出变量值
}                                  // main 函数结束
  1. 基础类型
cangjie 复制代码
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 函数结束
  1. 类型推断
cangjie 复制代码
main() {                           // 程序入口
    let score = 95                 // 初始值为整数,推断为 Int64
    let pi = 3.14                  // 初始值为小数,推断为 Float64

    println("${score}, ${pi}")     // 输出两个变量
}                                  // main 函数结束
  1. 函数定义与调用
cangjie 复制代码
func add(a: Int64, b: Int64): Int64 { // 定义函数 add,返回 Int64
    return a + b                       // 返回两数之和
}                                      // 函数结束

main() {                               // 程序入口
    println(add(3, 5))                 // 调用 add,输出 8
}                                      // main 函数结束
  1. 命名参数
cangjie 复制代码
func greet(name!: String): String {    // 定义命名参数函数,参数名后加 !
    return "你好,${name}"             // 返回问候语
}                                      // 函数结束

main() {                               // 程序入口
    println(greet(name: "小明"))       // 调用时必须写参数名 name:
}                                      // main 函数结束
  1. 命名参数带默认值
cangjie 复制代码
func greet(name!: String, greeting!: String = "你好"): String { // greeting 有默认值
    return "${greeting},${name}"                               // 返回拼接结果
}                                                               // 函数结束

main() {                                                        // 程序入口
    println(greet(name: "仓颉"))                                // 省略 greeting,使用默认值
    println(greet(name: "开发者", greeting: "欢迎"))            // 显式传入 greeting
}                                                               // main 函数结束
  1. if 分支
cangjie 复制代码
main() {                           // 程序入口
    let score = 85                 // 定义成绩,推断为 Int64

    if (score >= 90) {             // 条件必须用圆括号
        println("优秀")            // 90 分及以上
    } else if (score >= 60) {      // 否则继续判断是否及格
        println("及格")            // 60 分及以上
    } else {                       // 以上都不成立
        println("不及格")          // 低于 60 分
    }                              // if 结束
}                                  // main 函数结束
  1. while 循环
cangjie 复制代码
main() {                           // 程序入口
    var i = 1                      // 定义循环变量 i
    while (i <= 3) {               // 当 i <= 3 时循环
        println("while: ${i}")     // 输出当前 i
        i = i + 1                  // i 自增
    }                              // while 结束
}                                  // main 函数结束
  1. for-in 循环
cangjie 复制代码
main() {                           // 程序入口
    for (j in 1..=3) {             // 遍历闭区间 1 到 3
        println("for: ${j}")       // 输出当前 j
    }                              // for 结束
}                                  // main 函数结束
  1. 区间 ... 与 ...=
cangjie 复制代码
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 函数结束
  1. 字符串插值
cangjie 复制代码
main() {                           // 程序入口
    let a = 10                     // 定义变量 a
    let b = 20                     // 定义变量 b
    println("a + b = ${a + b}")    // 在字符串中嵌入表达式结果
}                                  // main 函数结束
  1. 注释
cangjie 复制代码
// 这是单行注释                // 从 // 到行尾都是注释

/*
 * 这是多行注释               // 多行注释开始
 * 可以写多行内容             // 中间内容
 */                           // 多行注释结束

main() {                      // 程序入口
    println("注释演示")       // 输出文本
}                             // main 函数结束

三、多元化习题、答案与解读

A. 选择题

题目1

仓颉程序的入口是?

A. func main()

B. main()

C. start()

D. init()

答案与解读:B。main 是仓颉约定的程序入口,顶层定义,不需要 func。

题目2

下列哪个关键字定义可变变量?

A. let

B. var

C. const

D. 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) { }。

题目5

1...=5 表示哪些整数?

A. 1、2、3、4

B. 1、2、3、4、5

C. 1、3、5

D. 5、4、3、2、1

答案与解读:B。...= 是闭区间,包含两端。

题目6

仓颉定义普通函数使用哪个关键字?

A. function

B. def

C. func

D. fn

答案与解读:C。仓颉用 func 定义普通函数。

题目7

命名参数在定义时,参数名后应加什么符号?

A. ?

B. !

C. @

D. #

答案与解读:B。定义命名参数时参数名后加 !,调用时必须写参数名。

题目8

仓颉合法整数类型是?

A. int

B. Integer

C. Int64

D. number

答案与解读:C。Int64 是仓颉整数类型之一。


B. 判断题

题目1

仓颉源文件扩展名是 .cj。

答案与解读:正确。仓颉源文件使用 .cj 后缀。

题目2

let 变量初始化后可以再次赋值。

答案与解读:错误。let 不可变,重新赋值需使用 var。

题目3

main 函数必须用 func 关键字定义。

答案与解读:错误。main 是特殊入口,不需要 func。

题目4

if 条件可以省略圆括号。

答案与解读:错误。if 条件必须用圆括号。

题目5

println 输出内容后会自动换行。

答案与解读:正确。println 输出后换行,print 不换行。

题目6

仓颉是静态强类型语言。

答案与解读:正确。仓颉是静态强类型语言。

题目7

字符串中 ${} 可以嵌入表达式。

答案与解读:正确。${} 内可写变量或表达式。

题目8

Unit 表示无值,类似其他语言的 void。

答案与解读:正确。Unit 表示无值。

题目9

变量类型标注不可省略。

答案与解读:错误。有初始值时通常可推断类型,可省略标注。

题目10

for (i in 1...5) 会遍历 1 到 5。

答案与解读:错误。1...5 是左闭右开,遍历 1 到 4;1...=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. 代码改错题

题目1

cangjie 复制代码
main() {                    // 程序入口
    let a = 10              // 定义不可变变量 a
    a = 20                  // 错误:let 不能重新赋值
    println(a)              // 输出 a
}                           // main 结束

答案与解读:

cangjie 复制代码
main() {                    // 程序入口
    var a = 10              // 将 let 改为 var,允许重新赋值
    a = 20                  // 修改 a 的值
    println(a)              // 输出 a
}                           // main 结束

let 不可重新赋值,需要改为 var。

题目2

cangjie 复制代码
main() {                    // 程序入口
    if x > 0 {              // 错误:条件缺少圆括号,x 未定义
        println("正数")     // 输出"正数"
    }                       // if 结束
}                           // main 结束

答案与解读:

cangjie 复制代码
main() {                    // 程序入口
    let x = 1               // 补充定义变量 x
    if (x > 0) {            // 条件必须加圆括号
        println("正数")     // 输出"正数"
    }                       // if 结束
}                           // main 结束

if 条件必须用圆括号;原代码中 x 也未定义。

题目3

cangjie 复制代码
func add(a: Int64, b: Int64) { // 错误:缺少返回类型
    return a + b               // 返回 a + b
}                              // 函数结束

答案与解读:

cangjie 复制代码
func add(a: Int64, b: Int64): Int64 { // 补充返回类型 Int64
    return a + b                       // 返回两数之和
}                                      // 函数结束

有 return 返回值时,应声明返回类型 : Int64。

题目4

cangjie 复制代码
main() {                    // 程序入口
    for (i in 1..5) {       // 左闭右开,只遍历 1 到 4
        println(i)          // 输出 i
    }                       // for 结束
}                           // main 结束

要求输出 1 2 3 4 5,如何修改?

答案与解读:

cangjie 复制代码
main() {                    // 程序入口
    for (i in 1..=5) {      // 改为闭区间,遍历 1 到 5
        println(i)          // 输出 i
    }                       // for 结束
}                           // main 结束

... 左闭右开,...= 才是包含右端点。

题目5

cangjie 复制代码
func greet(name!: String) { // 定义命名参数函数
    println("你好,${name}") // 输出问候语
}                           // 函数结束

main() {                    // 程序入口
    greet("小明")           // 错误:命名参数必须写参数名
}                           // main 结束

答案与解读:

cangjie 复制代码
func greet(name!: String) {    // 定义命名参数函数
    println("你好,${name}")    // 输出问候语
}                              // 函数结束

main() {                       // 程序入口
    greet(name: "小明")        // 命名参数调用时必须写参数名
}                              // main 结束

命名参数调用时必须写参数名 name:。


E. 输出预测题

题目1

cangjie 复制代码
main() {                               // 程序入口
    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 = 5,b = 3 + 5 = 8,a + b = 13。

题目2

cangjie 复制代码
main() {                    // 程序入口
    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。

题目3

cangjie 复制代码
func 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 == 1,isEven(7) 返回 false,进入 else。

题目4

cangjie 复制代码
main() {                    // 程序入口
    var i = 3               // i 初始为 3
    while (i > 0) {         // 当 i 大于 0 时循环
        println(i)          // 输出当前 i
        i = i - 1           // i 递减
    }                       // while 结束
}                           // main 结束

答案与解读:输出:

text 复制代码
3
2
1

while 循环,i 从 3 递减到 1。

题目5

cangjie 复制代码
func makeMsg(name!: String, greeting!: String = "你好"): String { // 命名参数,greeting 有默认值
    return "${greeting},${name}"                                 // 返回拼接后的消息
}                                                                 // 函数结束

main() {                                                          // 程序入口
    println(makeMsg(name: "仓颉"))                                // 使用默认 greeting
    println(makeMsg(name: "开发者", greeting: "欢迎"))            // 显式传入 greeting
}                                                                 // main 结束

答案与解读:输出:

text 复制代码
你好,仓颉
欢迎,开发者

greeting 有默认值,第一次调用省略;第二次显式传入。


F. 编程题

题目1

定义两个 Int64 变量,输出它们的和、差、积、商。

答案与解读:

cangjie 复制代码
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,判断是否为正数。

答案与解读:

cangjie 复制代码
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 中所有偶数的和。

答案与解读:

cangjie 复制代码
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。偶数序列 2+4+...+100,和为 2550。

题目4

编写函数 factorial(n: Int64): Int64,用 while 计算阶乘。

答案与解读:

cangjie 复制代码
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): String,90 及以上返回"优秀",60 及以上返回"及格",否则返回"不及格"。

答案与解读:

cangjie 复制代码
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,返回自我介绍。

答案与解读:

cangjie 复制代码
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、age,city 用默认
    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 到 4,1...=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 控制流程。

· 能使用 ${} 进行字符串插值。

· 能区分 ... 和 ...= 的区间含义。

· 能独立完成本课全部习题。

相关推荐
君顾11 小时前
本地AI错题纠正小程序:端侧推理与错题闭环实战
java·开发语言·错题
吠品1 小时前
Python 写入 Excel 的两种主流方案实际用法总结
c语言·开发语言·算法
M78佐菲1 小时前
ARM学习笔记(三)
linux·arm开发·笔记·嵌入式硬件·学习
邪修king1 小时前
Re:Linux 系统篇(三十一):库的制作与原理Chapter2:静态链接与程序加载 —— 从磁盘 ELF 到运行中进程的完整旅程
android·linux·运维·开发语言
geovindu1 小时前
rust: Factory Method Pattern
开发语言·设计模式·rust·工厂方法模式·创建型模式
eybk1 小时前
用Kivy制作手机相片分类局域网传送工具,还能传输数据库文件
开发语言·python
传奇开心果编程1 小时前
【ArkUI 练中学】第4课:高级布局与列表性能优化
学习·华为·前端框架
企业数字化笔记1 小时前
固定资产还有借用记录能报废吗?Java前置检查、停止折旧与SQL验收
java·开发语言·sql
dtq04241 小时前
数据结构 - 栈
c语言·数据结构·学习