ワンクリックで
cangjie-lang
Cangjie programming language code generation and analysis expert. Use this when users need to write or analyze Cangjie code.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Cangjie programming language code generation and analysis expert. Use this when users need to write or analyze Cangjie code.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| 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