with one click
cangjie-lang
// Cangjie programming language code generation and analysis expert. Use this when users need to write or analyze Cangjie code.
// Cangjie programming language code generation and analysis expert. Use this when users need to write or analyze Cangjie code.
| name | cangjie-lang |
| description | Cangjie programming language code generation and analysis expert. Use this when users need to write or analyze Cangjie code. |
.cjcj(Cangjie)main()// 单行注释
/*
* 多行注释
*/
/**
* 文档注释
*/
main() {
// 代码主体
let a: Int64 = 20
var b: Int64 = 12
println("${a}${b}")
}
修饰符 变量名: 变量类型 = 初始值
let - 不可变变量(只能赋值一次,初始化后不可修改)var - 可变变量(可以被多次赋值)⚠️ 易错点1:let 不支持变量遮蔽(shadowing),不能在同一作用域内重新定义同名变量。
| 修饰符 | 范围 | 默认值 |
|---|---|---|
private | class定义内可见 | ❌ |
public | 模块内外均可见 | ❌ |
protected | 当前模块及当前类的子类可见 | ❌ |
internal | 仅当前包及子包内可见 | ✅ 默认 |
static - 影响成员变量的存储和引用方式main() {
let a: Int64 = 20 // 不可变变量
var b: Int64 = 12 // 可变变量
b = 23 // 可以修改var变量
println("${a}${b}")
}
示例参考:examples/01_variable_declaration.cj
有符号整数:Int8、Int16、Int32、Int64、IntNative
无符号整数:UInt8、UInt16、UInt32、UInt64、UIntNative
浮点类型:Float16、Float32、Float64
布尔类型:true、false
Rune 表示,可以表示 Unicode 字符集中的所有字符UInt32(e) - 获取 Unicode scalar valueRune(num) - 值必须在有效 Unicode 范围内
[0x0000, 0xD7FF] 或 [0xE000, 0x10FFFF]⚠️ 易错点2:Rune 转整数时需确保在有效 Unicode 范围内,否则会编译错误或运行时抛异常。
let slash: Rune = r'\\'
let newLine: Rune = r'\n'
let tab: Rune = r'\t'
let he: Rune = r'\u{4f60}' // 你
let llo: Rune = r'\u{597d}' // 好
仓颉支持三种字符串字面量:
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}"
适用范围:插值字符串仅适用于单行字符串字面量和多行字符串字面量,不适用于多行原始字符串字面量。
(T1, T2, ..., TN)(Int64, Float64)、(Int64, Float64, String)tuple[0]、tuple[1]var tuple = (true, false)
println(tuple[0])
Array<T> // T 是元素类型,可以是任意类型
Range<T>(泛型)start、end、stepstart 和 end 类型相同(T)step 类型是 Int64step 值不能等于 0()示例参考:examples/02_basic_types.cj
⚠️ 易错点5:条件表达式的括号不能省略,这是与很多语言的差异。
if (条件) { // ✅ 必须有括号
分支 1
} else {
分支 2
}
基本形式:
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 (条件) {
循环体
}
// do-while 形式
do {
循环体
} while (条件)
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、continuegoto示例参考:examples/03_control_flow.cj
语法:(参数类型) -> 返回类型
() 括起,多个参数用 , 分隔-> 连接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 // 可以直接返回函数
}
语法:
{ 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
enum 开头| 分隔| 是可选的enum RGBColor {
| Red(UInt8) | Green(UInt8) | Blue(UInt8)
}
CC(p1, p2, ..., pn)示例参考:examples/05_enum.cj
基本语法:
⚠️ 重要:case 后的语句不需要 {} 括号,多行语句直接换行即可
match (待匹配值) {
case 模式1 => 处理1
case 模式2 => 处理2
case _ => 默认处理 // 通配符
}
多行语句:直接换行,不需要 {}
match (value) {
case 1 => println("one")
case 2 => println("two")
println("second number") // ✅ 多行直接换行
case _ => println("other")
}
示例:
main() {
let x = 0
match (x) {
case 1 => print("x = 1")
case 0 => print("x = 0") // 匹配
case 2 | 3 | 4 => print("other") // 多值匹配
case _ => print("其他")
}
}
支持:整数字面量、浮点数字面量、字符字面量、布尔字面量、字符串字面量、Unit 字面量
⚠️ 易错点10:不支持字符串插值
使用 _ 表示,匹配任意值,通常作为最后一个 case
使用标识符,匹配并绑定值
main() {
let x = -10
let y = match (x) {
case 0 => "zero"
case n => "x is not zero and x = ${n}" // n 绑定匹配的值
}
println(y)
}
用于匹配元组值
main() {
let tv = ("Alice", 24)
let s = match (tv) {
case ("Bob", age) => "Bob is ${age} years old"
case ("Alice", age) => "Alice is ${age} years old" // age 是绑定模式
case (name, 100) => "${name} is 100 years old"
case (_, _) => "someone"
}
println(s)
}
判断运行时类型是否是某个类型的子类型
main() {
var d = Derived()
var r = match (d) {
case b: Base => b // b 是类型模式,匹配 Base 类型
case _ => 0
}
println("r = ${r}")
}
用于匹配 enum 类型的实例
enum TimeUnit {
| Year(UInt64)
| Month(UInt64)
}
main() {
let x = Year(2)
let s = match (x) {
case Year(n) => "x has ${n * 12} months" // 匹配
case TimeUnit.Month(n) => "x has ${n} months" // TimeUnit.Month 是完整路径
}
println(s)
}
⚠️ 重要:Tuple 模式和 enum 模式可以嵌套任意模式
enum TimeUnit {
| Year(UInt64)
| Month(UInt64)
}
enum Command {
| SetTimeUnit(TimeUnit)
| GetTimeUnit
| Quit
}
main() {
let command = (SetTimeUnit(Year(2022)), SetTimeUnit(Year(2024)))
match (command) {
case (SetTimeUnit(Year(year)), _) => println("Set year ${year}")
case (_, SetTimeUnit(Month(month))) => println("Set month ${month}")
case _ => ()
}
}
在 case 的模式之后,可以使用 where 子句添加额外的条件判断(称为 pattern guard)。
语法:case 模式 where 条件 => 处理
⚠️ 重要:使用 where 关键字,不是 if
示例:
enum RGBColor {
| Red(Int16)
| Green(Int16)
| Blue(Int16)
}
main() {
let c = RGBColor.Green(-100)
let cs = match (c) {
case Red(r) where r < 0 => "Red = 0"
case Red(r) => "Red = ${r}"
case Green(g) where g < 0 => "Green = 0" // 匹配(因为 -100 < 0)
case Green(g) => "Green = ${g}"
case Blue(b) where b < 0 => "Blue = 0"
case Blue(b) => "Blue = ${b}"
}
println(cs) // 输出:Green = 0
}
注意事项:
where 后的条件表达式必须是 Bool 类型if,应该使用 where错误示例:
match (value) {
case n if n > 0 => println("positive") // ❌ 编译错误:不是 if
case _ => println("other")
}
正确写法:
match (value) {
case n where n > 0 => println("positive") // ✅ 使用 where
case _ => println("other")
}
示例参考:examples/06_pattern_matching.cj
enum Option<T> {
| Some(T) // 有值
| None // 无值
}
当需要表示某个类型可能有值,也可能没有值的时候使用。
??let optA: Option<Int64> = Option<Int64>.Some(42)
let a: Int64 = optA ?? 0 // 如果 optA 是 None,则使用默认值 0
let optA: Option<Int64> = Option<Int64>.Some(42)
if (optA.isSome()) {
println("有值")
}
if (optA.isNone()) {
println("无值")
}
let optA: Option<Int64> = Option<Int64>.Some(42)
if (let Option<Int64>.Some(a) <- optA) {
println("值是: ${a}")
} else {
println("无值")
}
func getValue(): Option<Int64> {
// ... 一些逻辑
return Option<Int64>.None
}
func process(): Int64 {
let optA = getValue()
let a = optA ?? return 0 // 如果是 None,直接返回 0
// 继续处理 a
a + 1
}
func getValue(): Option<Int64> {
return Option<Int64>.None
}
func processOrThrow(): Int64 {
let optA = getValue()
let a = optA ?? throw Exception("值不存在")
// 继续处理 a
a
}
let optA: Option<Int64> = Option<Int64>.Some(42)
let result = match (optA) {
case Option<Int64>.Some(value) => "值是: ${value}"
case Option<Int64>.None => "无值"
}
示例参考:examples/07_option_type.cj
class ClassName {
// 成员变量
// 成员属性
// 静态初始化器
// 构造函数
// 成员函数
// 操作符函数
}
class Rectangle {
let width: Int64
let height: Int64
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
}
public func area() {
width * height
}
}
let rec = Rectangle(10, 20)
let l = rec.height // l = 20
对于 class 的成员(变量、属性、构造函数、函数):
| 修饰符 | 含义 | 默认 |
|---|---|---|
private | class 定义内可见 | ❌ |
internal | 当前包及子包(含子包的子包)内可见 | ✅ 默认 |
protected | 当前模块及当前类的子类可见 | ❌ |
public | 模块内外均可见 | ❌ |
⚠️ 易错点11:成员的默认访问修饰符是 internal,不是 private 或 public。
示例参考:examples/08_class.cj
@Test - 应用于顶级函数或类,转换为单元测试类@TestCase - 标记测试类内的函数为测试用例@Fail - 标记测试失败@Assert(leftExpr, rightExpr) // 判断相等
@Assert(condition: Bool) // 判断条件
@Expect(leftExpr, rightExpr) // 判断相等
@Expect(condition: Bool) // 判断条件
@Test
class LexerTest {
@TestCase
func test() {
let a = 1
// 方式一:手动判断
if (a != 1) {
@Fail("a is not 1")
}
// 方式二:Assert 条件
@Assert(a != 1)
// 方式三:Assert 相等
@Assert(a, 1)
}
}
示例参考:examples/09_unit_test.cj
// 抛出异常
throw Exception("错误信息")
// 捕获异常
try {
// 可能抛出异常的代码
} catch (e: ExceptionType) {
// 处理异常
}
示例参考:examples/10_error_handling.cj
main() {
// 条件判断(必须有括号)
if (条件) {
// ...
} else {
// ...
}
// 循环
while (条件) { }
do { } while (条件)
for (变量 in 序列) { }
// 模式匹配
match (值) {
case 模式 => 处理
case _ => 默认
}
}
| 类型 | 后缀 |
|---|---|
| 整数 | Int8, Int16, Int32, Int64, IntNative |
| 无符号整数 | UInt8, UInt16, UInt32, UInt64, UIntNative |
| 浮点 | Float16, Float32, Float64 |
| 字符 | Rune |
| 字符串 | String |
| 元组 | (T1, T2, ...) |
| 数组 | Array<T> |
| 区间 | Range<T> |
| 函数 | (T1, T2) -> Rt |
示例参考:examples/11_quick_reference.cj
仓颉提供了多种集合类型,适用于不同的使用场景:
1. Array - 固定大小数组
let arr: Array<String> = ["A", "B", "C"]main() {
// 创建 Array
let arr: Array<String> = ["A", "B", "C"]
// 访问元素(使用下标)
println(arr[0]) // 输出: A
// 修改元素
arr[0] = "X"
println(arr[0]) // 输出: X
// 获取大小
println(arr.size) // 输出: 3
}
2. ArrayList - 动态数组
import std.collection.ArrayList
main() {
// 创建 ArrayList
let list = ArrayList<Int64>()
// 添加元素(使用 add 方法)
list.add(1, at: 0) // 在位置 0 添加 1
list.add(2, at: 1) // 在位置 1 添加 2
// 或使用 add 添加整个数组
let arr = [3, 4, 5]
list.add(all: arr) // list: [1, 2, 3, 4, 5]
// 访问元素(使用 get 方法,返回 Option)
let value = list.get(0)
match (value) {
case Option<Int64>.Some(v) => println("First: ${v}")
case Option<Int64>.None => println("Not found")
}
// 或使用下标访问
println(list[0]) // 输出: 1
// 修改元素
list[0] = 10
// 删除元素
list.remove(at: 0) // 移除第一个元素
// 获取大小
println(list.size)
}
3. HashSet - 哈希集合
import std.collection.HashSet
main() {
// 创建 HashSet
let set = HashSet<Int64>()
// 添加元素
set.add(1)
set.add(2)
set.add(3)
set.add(1) // 重复元素不会被添加
// 检查是否包含
if (set.contains(2)) {
println("包含 2")
}
// 获取大小
println(set.size) // 输出: 3
// 删除元素
set.remove(2)
}
4. HashMap - 哈希映射
let map: HashMap<String, Int> = HashMap(("A", 1), ("B", 2)) 或 HashMap([("A", 1), ("B", 2)])import std.collection.HashMap
main() {
// 创建 HashMap(使用字面量)
let map: HashMap<String, Int64> = HashMap(
("A", 1),
("B", 2),
("C", 3)
)
// 或者使用方括号
let map2: HashMap<String, Int64> = HashMap([
("A", 1),
("B", 2),
("C", 3)
])
// 或者空 HashMap
let emptyMap = HashMap<String, Int64>()
// 添加元素(使用 add 方法)
emptyMap.add("D", 4)
// 访问元素(使用 get 方法,返回 Option)
let value = map.get("A")
match (value) {
case Option<Int64>.Some(v) => println("A = ${v}")
case Option<Int64>.None => println("Not found")
}
// 或使用下标访问
println(map["A"]) // 输出: 1
// 修改元素
map["A"] = 10
// 检查是否包含键
if (map.contains("B")) {
println("包含键 B")
}
// 删除元素
map.remove("C")
// 获取大小
println(map.size)
}
添加元素:
add(element, at: index) 或 add(all: array)add(element)add(key, value) 或 map[key] = value访问元素:
array[index] 或 array.get(index)list[index] 或 list.get(index)(返回 Option)map[key] 或 map.get(key)(返回 Option)修改元素:
[] 下标方式修改删除元素:
remove(at: index)remove(element)remove(key)其他常用方法:
size - 获取元素个数(属性)clear() - 清空所有元素(ArrayList, HashSet, HashMap)contains(element) - 检查是否包含(HashSet, HashMap)get(index) - 获取元素(ArrayList, HashMap,返回 Option)示例参考:examples/12_collections.cj
仓颉使用包(package)来组织代码,提供模块化和命名空间管理。
基本语法:
package package.name
目录结构与包声明对应:
src
└── directory_0
├── directory_1
│ ├── a.cj // package demo.directory_0.directory_1
│ └── b.cj // package demo.directory_0.directory_1
└── c.cj // package demo.directory_0
└── main.cj // package demo
示例:
// a.cj
package demo.directory_0.directory_1
public func funcA() {
println("Function A")
}
// b.cj
package demo.directory_0.directory_1
public func funcB() {
println("Function B")
}
// c.cj
package demo.directory_0
public func funcC() {
println("Function C")
}
// main.cj
package demo
import demo.directory_0.directory_1.{funcA, funcB}
import demo.directory_0.funcC
main() {
funcA() // 调用 demo.directory_0.directory_1.funcA
funcB() // 调用 demo.directory_0.directory_1.funcB
funcC() // 调用 demo.directory_0.funcC
}
基本语法:
package currentPackage
import std.math.* // 导入 std.math 的所有内容
import package1.foo // 导入 package1.foo
import {package1.foo, package2.bar, package1.MyClass} // 导入多个
使用示例:
package demo
import std.math.*
import package1.helper
import {package1.MyClass, package2.Utils}
main() {
// 直接使用导入的方法和类型
let result = pow(2, 3) // std.math.pow
helper() // package1.helper
let obj = MyClass() // package1.MyClass
Utils.doSomething() // package2.Utils
}
1. 导入所有(通配符):
import std.math.*
// 可以直接使用 std.math 中的所有内容
let value = sqrt(16)
2. 导入特定项:
import std.math.pi
// 只能使用 pi
println(pi)
3. 导入多个项:
import {std.math.sin, std.math.cos}
// 可以使用 sin 和 cos
4. 重命名导入:
import std.math as math
let value = math.sqrt(16)
示例:
package demo.math
// 默认为 internal,仅 demo.math 及其子包可见
func internalFunc() {
println("internal")
}
// public,任何地方都可访问
public func publicFunc() {
println("public")
}
// private,仅当前文件可见
private func privateFunc() {
println("private")
}
示例参考:examples/13_package_import.cj
需求识别:
生成步骤:
templates/ 目录)示例模板:
// templates/basic/variable_declaration.cj.template
{{MODIFIER}} {{VARIABLE_NAME}}: {{TYPE}} = {{INIT_VALUE}}
需求识别:
生成步骤:
var 修饰(默认let)需求识别:
生成步骤:
break/continue(不支持标签,易错点6/7)需求识别:
生成步骤:
internal(易错点11)需求识别:
生成步骤:
需求识别:
生成步骤:
@Test 和 @TestCase 宏分析步骤:
检查项:
${}⚠️分析步骤:
重点检测:
分析步骤:
优化项:
⚠️ let 不支持变量遮蔽
⚠️ 函数参数默认是 let 不可变的
var 显式声明可变参数⚠️ 成员变量默认访问修饰符是 internal
private⚠️ 所有条件表达式必须有括号
if x > 0 { }if (x > 0) { }⚠️ 不支持 goto
⚠️ break/continue 不支持标签跳转
break outerLoop;⚠️ Rune 转整数需确保在有效 Unicode 范围
Rune(0xD800) (代理区字符)[0x0000, 0xD7FF] 或 [0xE000, 0x10FFFF]⚠️ 原始字符串字面量中转义字符不会被转义
##"\n"## 会产生换行符"\\n" 或理解原始字符串特性⚠️ match 表达式的 case 按顺序匹配
_ 放在最后⚠️ 常量模式不支持字符串插值
"Hello ${name}"${} 而非 {}
"Hello {name}""Hello ${name}"{ => 123 }() 是合法语法,立即执行Lambda() 进行其他操作(如算术运算)⚠️ 元组至少需要两个元素
⚠️ 区间类型的 step 不能等于 0
Range(1, 10, 0)⚠️ enum 至少存在一个有名字的构造器
⚠️ match 表达式的 case 不需要 {} 括号
case 1 => { println("1") }case 1 => println("1")⚠️ Option 类型用于表示可能有值或无值
⚠️ Duration 和 sleep 在 std.core 里不需导入
共39个示例,按难度和语法模块分类:
基础示例(01-15):
中级示例(16-27):
高级示例(28-39):
按场景组织:
basic/:
functions/:
control_flow/:
data_structures/:
testing/:
生成代码时必须确保:
${}分析代码时必须提供:
优先级:
触发条件:
当前可用的MCP工具:
search_documents - 搜索仓颉文档
get_document_content - 获取文档内容
list_documents - 列出文档
get_document_overview - 获取文档总览
# 查询lambda相关文档
search_documents(query="lambda closure")
# 获取某个文档的特定章节
get_document_content(
doc_id="manual_source_zh_cn_functions",
section="lambda"
)
# 浏览标准库结构
list_documents(category="libs", subcategory="std")
let、var、if、else、while、do、for、match、case、func、class、enum、init、return、package、import、public、private、protected、internal、static
std.core - 核心类型和函数std.io - 输入输出std.collection - 集合类型std.time - 时间和日期欢迎贡献新的示例、模板和改进建议!
贡献方式:
质量要求:
MIT License
结束
文档维护:仓颉语言社区 最后更新:2025-01-07 版本:v1.0.0