| name | cangjie-lang |
| description | Cangjie programming language code generation and analysis expert. Use this when users need to write or analyze Cangjie code. |
仓颉语言代码生成与分析工作手册
目录
第1章:语言基础定义
1.1 文件与后缀
- 文件后缀:
.cj
- 语言简称:
cj(Cangjie)
- 入口函数:
main()
1.2 注释
// 单行注释
/*
* 多行注释
*/
/**
* 文档注释
*/
1.3 代码块结构
main() {
// 代码主体
let a: Int64 = 20
var b: Int64 = 12
println("${a}${b}")
}
第2章:核心语法规则
2.1 变量声明
语法格式
修饰符 变量名: 变量类型 = 初始值
可变性修饰符
let - 不可变变量(只能赋值一次,初始化后不可修改)
var - 可变变量(可以被多次赋值)
⚠️ 易错点1:let 不支持变量遮蔽(shadowing),不能在同一作用域内重新定义同名变量。
可见性修饰符
| 修饰符 | 范围 | 默认值 |
|---|
private | class定义内可见 | ❌ |
public | 模块内外均可见 | ❌ |
protected | 当前模块及当前类的子类可见 | ❌ |
internal | 仅当前包及子包内可见 | ✅ 默认 |
静态性修饰符
示例代码
main() {
let a: Int64 = 20 // 不可变变量
var b: Int64 = 12 // 可变变量
b = 23 // 可以修改var变量
println("${a}${b}")
}
示例参考:examples/01_variable_declaration.cj
2.2 基础类型
数值类型
有符号整数:Int8、Int16、Int32、Int64、IntNative
无符号整数:UInt8、UInt16、UInt32、UInt64、UIntNative
浮点类型:Float16、Float32、Float64
布尔类型:true、false
字符类型(Rune)
- 使用
Rune 表示,可以表示 Unicode 字符集中的所有字符
- Rune → UInt32:
UInt32(e) - 获取 Unicode scalar value
- 整数 → Rune:
Rune(num) - 值必须在有效 Unicode 范围内
- 有效范围:
[0x0000, 0xD7FF] 或 [0xE000, 0x10FFFF]
⚠️ 易错点2:Rune 转整数时需确保在有效 Unicode 范围内,否则会编译错误或运行时抛异常。
转义字符
let slash: Rune = r'\\'
let newLine: Rune = r'\n'
let tab: Rune = r'\t'
Unicode 字面量
let he: Rune = r'\u{4f60}' // 你
let llo: Rune = r'\u{597d}' // 好
字符串类型(String)
仓颉支持三种字符串字面量:
1. 单行字符串字面量
内容定义在一对单引号或双引号内,只能写在同一行:
let s1: String = ""
let s2 = 'Hello Cangjie Lang'
let s3 = "\"Hello Cangjie Lang\""
let s4 = 'Hello Cangjie Lang\n' // \n 是转义字符,表示换行
2. 多行字符串字面量
开头结尾需各存在三个双引号(""")或三个单引号('''),内容从开头的三个引号换行后的第一行开始:
// 三个双引号
let s1: String = """
""" // 空字符串(换行后才开始)
// 三个单引号
let s2: String = '''
Hello,
Cangjie Lang'''
3. 多行原始字符串字面量
以一个或多个井号(#)和一个单引号或双引号开头,转义规则不适用,不支持插值:
let s1: String = #""# // 空字符串
let s2 = ##'#'\n'## // \n 不是换行符,是 \ 和 n 两个字符
let s3 = ###"
Hello,
Cangjie
Lang"### // 保留换行和缩进
⚠️ 易错点4:在多行原始字符串字面量中,转义字符(如 \n、\t)不会被转义,字面量中的内容会维持原样。
⚠️ 易错点5:多行原始字符串字面量不支持插值,不要使用 ${} 语法。
插值字符串
⚠️ 易错点3:插值字符串中使用 ${} 表达式
let fruit = "apples"
let count = 10
let s = "There are ${count * count} ${fruit}"
适用范围:插值字符串仅适用于单行字符串字面量和多行字符串字面量,不适用于多行原始字符串字面量。
元组(Tuple)
- 类型表示:
(T1, T2, ..., TN)
- 至少二元:
(Int64, Float64)、(Int64, Float64, String)
- 索引访问:
tuple[0]、tuple[1]
var tuple = (true, false)
println(tuple[0])
数组类型
Array<T> // T 是元素类型,可以是任意类型
区间类型(Range)
- 类型表示:
Range<T>(泛型)
- 包含三个值:
start、end、step
- 约束:
start 和 end 类型相同(T)
step 类型是 Int64
step 值不能等于 0
Unit 类型
- 唯一值:
()
- 支持操作:仅赋值、判等、判不等
- ⚠️ 不支持:其他所有操作
示例参考:examples/02_basic_types.cj
2.3 表达式与控制流
条件表达式
⚠️ 易错点5:条件表达式的括号不能省略,这是与很多语言的差异。
if (条件) { // ✅ 必须有括号
分支 1
} else {
分支 2
}
if 表达式
基本形式:
if (条件) {
分支 1
} else {
分支 2
}
if 作为表达式(返回值):
let a = 10
let result = if (a > 5) {
"greater than 5"
} else {
"5 or less"
}
// result = "greater than 5"
模式匹配(let pattern):
let a = Some(3)
let d = Some(1)
if (let Some(e) <- a && let Some(f) <- d) { // 两个模式都匹配
println("${e} ${f}") // 输出: 3 1
}
while 表达式
while (条件) {
循环体
}
// do-while 形式
do {
循环体
} while (条件)
for-in 表达式
for (迭代变量 in 序列) {
循环体
}
元组遍历:
let array = [(1, 2), (3, 4), (5, 6)]
for ((x, y) in array) {
println("${x}, ${y}")
}
区间遍历:
main() {
var sum = 0
for (i in 1..=100) { // 1 到 100(包含)
sum += i
}
println(sum)
}
跳转控制
- 支持
break、continue
- ⚠️ 易错点6:不支持标签跳转
- ⚠️ 易错点7:完全不支持
goto
示例参考:examples/03_control_flow.cj
2.4 函数
函数是一等公民
- 可以作为函数的参数或返回值
- 可以赋值给变量
- 函数本身也有类型
函数类型
语法:(参数类型) -> 返回类型
- 参数类型用
() 括起,多个参数用 , 分隔
- 参数类型和返回类型用
-> 连接
func add(a: Int64, b: Int64): Int64 {
return a + b
}
type FnType = (Int64) -> Unit
func display(a: Int64): Unit {
println(a)
}
// 命名参数
func name(name!:String)
// 命名参数还可以设置默认值
func name(name!:String = "小王")
函数参数
⚠️ 易错点8:函数参数默认是 let 定义的不可变变量
// a 和 b 默认是 let 不可变的(不能显式写 let 或 var)
func add(a: Int64, b: Int64): Int64 {
return a + b
}
⚠️ 重要:
- 函数参数不能显式使用
let 或 var 修饰符(包括顶层函数、class成员方法、struct成员方法等所有函数)
- 参数默认就是
let 不可变的
如果需要修改参数值,应该使用局部变量:
func modify(a: Int64): Int64 {
var result = a
result = result + 1 // 修改局部变量
return result
}
返回值简写
func add(a: Int64, b: Int64): Int64 {
a + b // 最后一个表达式自动作为返回值
}
func returnAdd(): (Int64, Int64) -> Int64 {
add // 可以直接返回函数
}
Lambda 表达式
语法:
{ p1: T1, ..., pn: Tn => expressions | declarations }
示例:
// 完整类型声明
let f1 = { a: Int64, b: Int64 => a + b }
// 无参 Lambda
var display = { =>
println("Hello")
println("World")
}
// 类型推断
var sum1: (Int64, Int64) -> Int64 = { a, b => a + b }
var sum2: (Int64, Int64) -> Int64 = { a: Int64, b => a + b }
// Lambda 作为参数
func f(a1: (Int64) -> Int64): Int64 {
a1(1)
}
main(): Int64 {
f({ a2 => a2 + 10 }) // 参数类型推断
}
Lambda 立即调用:
⚠️ 易错点9:Lambda 表达式可以立即调用
let r2 = { => 123 }() // r2 = 123,立即执行
var g = { x: Int64 => println("x = ${x}") }
g(2) // 调用 Lambda
示例参考:examples/04_functions.cj
2.5 枚举类型
定义语法