function
SKILL.md
仓颉语言函数 Skill
1. 函数定义
1.1 基本语法
func functionName(param1: Type1, param2: Type2): ReturnType {
// 函数体
}
- 关键字
func开头 - 参数在
()内,逗号分隔 - 返回类型在参数列表后的
:之后(可选,编译器可推断) - 函数体在
{}内
1.2 参数列表
- 非命名参数:
p: T— 位置参数,调用时无标签 - 命名参数:
p!: T— 定义时使用!后缀,调用时使用p: value形式(调用不需要写!) - 带默认值的命名参数:
p!: T = expr— 仅命名参数可有默认值,使用=赋值 - 顺序规则:非命名参数须在命名参数之前,命名参数后不能跟非命名参数
- 不可变性:所有函数参数在函数体内不可变(不能重新赋值)
- 作用域:参数名从定义处到函数体结束有效。在函数体内重新定义同名变量会报错
- 命名参数完整示例:
// 函数定义,其中 indent 是命名参数,默认值为 2 func serializePretty(value: JsonValue, indent!: Int64 = 2): String { ... } // 函数调用,命名参数 indent 使用前缀传值(注意不带 ! 符号) serializePretty(value, indent: 4) // 省略命名参数时使用默认值 serializePretty(value) // indent 使用默认值 2
1.3 返回类型
- 可显式声明或省略(编译器推断)
- 若已声明,所有
return e表达式和函数体的最终表达式须为声明类型的子类型 - 若返回类型为
Unit,编译器自动在所有返回点插入return () - 若推断失败,编译器报错
1.4 函数体
- 包含变量定义、表达式、以及可选的嵌套函数定义
return expr:终止执行,返回expr(须匹配返回类型)return:等价于return (),须要求Unit返回类型return表达式的类型为Nothing- 函数体类型 = 最后一项的类型:表达式 → 该表达式类型;变量定义/函数声明/空 →
Unit
2. 函数调用
2.1 基本调用语法
f(arg1, arg2, ..., argn)
- 每个实参的类型须为对应形参类型的子类型
2.2 非命名参数调用
- 按位置传递表达式:
add(x, y)
2.3 命名参数调用
- 使用
paramName: value语法:add(b: y, a: x) - 命名实参的顺序可以与定义顺序不同
2.4 默认值
- 若调用时未提供带默认值的命名参数,则使用默认值
- 若提供了新值,则覆盖默认值
3. 函数类型 / 一等公民
3.1 函数类型语法
(ParamType1, ParamType2, ...) -> ReturnType->右结合- 示例:
() -> Unit— 无参,返回 Unit(Int64, Int64) -> Int64— 两个 Int64 参数,返回 Int64() -> (Int64, Int64) -> Int64— 返回一个函数
3.2 类型参数名
- 函数类型可选包含参数名:
(name: String, price: Int64) -> Unit - 须全部具名或全部不具名,不可混合
3.3 函数作为一等值
- 函数可赋给变量、作为参数传递、从函数返回
- 函数名本身是该函数类型的表达式
- 若函数名重载且有歧义,直接赋给无类型标注的变量会报错。显式类型标注可消除歧义:
var plus: (Int64, Int64) -> Int64 = add // 消除歧义
4. Lambda 表达式
4.1 Lambda 语法
{ p1: T1, p2: T2 =>
exprs
}
=>分隔参数和函数体,不可省略(尾随 Lambda 除外)- 函数体是 exprs(1~N 个表达式/定义),多个时各占一行
- Lambda 的值/类型 = 函数体最后一个表达式的值/类型
- 无参 Lambda:
{ => exprs } - 参数类型可省略(当可从上下文推断时)
- 返回类型始终推断,不可显式声明
4.2 返回类型推断
- 从变量类型标注、函数参数类型或外围函数返回类型推断
- 若无上下文,从函数体最后一个表达式的类型推断(空体为
Unit)
4.3 Lambda 调用
- 立即调用:
{ a: Int64, b: Int64 => a + b }(1, 2) - 通过变量调用:赋给变量,使用
variableName(args)调用
5. 闭包
5.1 定义
闭包 = 函数/Lambda + 从其定义(词法)作用域捕获的变量
5.2 什么算作变量捕获
- 访问在函数/Lambda 外部定义的局部变量
- 在默认参数值中访问函数外部的变量
- 在类/结构体中,非成员函数/Lambda 访问实例成员或
this
5.3 什么不算作捕获
- 访问自身的局部变量或参数
- 访问全局变量或静态成员变量
- 实例成员函数中通过隐式
this访问实例成员
5.4 捕获规则
- 被捕获的变量须在闭包定义处可见
- 被捕获的变量须在闭包定义前已初始化
- 若捕获的变量为引用类型,其可变实例成员可被修改
- 捕获
var的闭包不能逃逸:不能赋给变量、返回、作为参数传递或作为独立表达式 — 只能直接调用 - 传递性捕获:若函数
f调用捕获了var变量的函数g(该var非f的局部变量),则f也被视为捕获了var,不能逃逸 - 静态/全局
var变量不算捕获 — 访问它们的函数仍为一等值
6. 嵌套函数
- 在其他函数体内定义的函数
- 作用域:仅在外围函数内可见
- 可访问外围函数的变量和参数
- 可在外围函数中调用或作为值返回
- 生命周期:每次外围函数调用时创建,外围函数结束时销毁(除非作为闭包返回/捕获)
7. 函数重载
7.1 重载规则
- 同名、不同参数数量或类型 → 有效重载
- 泛型函数:对齐类型参数名后,若非泛型部分不同 → 重载;否则 → 重定义错误。类型变量约束不参与判断
- 构造函数:同一类中不同参数的构造函数 → 重载
- 主构造函数与
init:不同参数 → 重载 - 不同作用域(均可见)中的同名函数 → 重载
- 子类与父类同名函数不同参数类型 → 重载
7.2 不能重载的情况
- 同一类/接口/结构体中同名的静态函数与实例函数(即使参数不同也不行):
class Parser { // 错误:不能同时定义同名的实例方法和静态方法 // public func parse(): Result { ... } // public static func parse(source: String): Result { ... } } - 枚举构造函数与静态/实例成员函数
- 函数类型的变量不能互相重载
- 变量和函数不能同名
7.3 重载解析
- 内层作用域优先:嵌套作用域中最内层匹配的函数优先
- 最具体匹配:同一作用域层级中,参数类型最具体(最窄)的函数被选择
- 父/子类视为同一作用域进行解析 — 更具体的匹配优先
- 若无唯一最佳匹配 → 错误
8. 运算符重载
8.1 语法
public operator func +(right: Point): Point { ... }
public operator func -(): Point { ... } // 一元运算符
- 在
func前使用operator修饰符 - 一元运算符:无参数(操作
this) - 二元运算符:一个参数(右操作数;左操作数为
this) - 只能在 class、interface、struct、enum、extend 中定义
- 不能 为
static,不能 为泛型 - 不改变原有优先级或结合性
8.2 可重载的运算符
()、[]、!、-(一元)、**、*、/、%、+、-(二元)、<<、>>、<、<=、>、>=、==、!=、&、^、|
8.3 索引运算符 []
- 取值形式:
operator func [](args...): ReturnType— 仅非命名参数 - 赋值形式:
operator func [](args..., value!: T): Unit— 须有唯一命名参数value!,无默认值,返回Unit - 可仅重载取值或赋值中的一个
8.4 函数调用运算符 ()
operator func ()(params): ReturnType— 任意参数/返回类型- 不能通过
this()或super()调用(它们始终引用构造函数)
8.5 复合赋值
- 重载二元运算符(关系运算除外)时自动启用对应复合赋值版本(
+=、-=等),前提是返回类型与左操作数类型匹配或为其子类型
8.6 限制
- 不能创建自定义运算符(仅限列出的运算符)
- 不能重新重载类型已原生支持的运算符(如
Int64的+)
9. 函数调用语法糖
9.1 尾随 Lambda
- 当最后一个参数为函数类型且实参为 Lambda 时,Lambda 可置于括号外部:
myIf(true) { 100 } - 若函数仅有一个参数(Lambda),括号可完全省略:
f { i => i * i } - 在尾随 Lambda 位置,
=>可省略
9.2 管道运算符 |>
e1 |> e2等价于let v = e1; e2(v)e2须为函数类型表达式;e1的类型须为e2参数类型的子类型- 可链式使用:
arr |> inc |> sum - 不能直接用于有非默认命名参数的函数(需用 Lambda 包装)
9.3 组合运算符 ~>
f ~> g等价于{ x => g(f(x)) }f和g须为单参数函数f的返回类型须为g的参数类型的子类型
9.4 变长参数
- 当最后一个非命名参数为
Array<T>时,调用者可直接传递 0 个或多个值(而非数组字面量):func sum(arr: Array<Int64>) { ... } sum(1, 2, 3) // 脱糖为 sum([1, 2, 3]) - 仅最后一个非命名参数可变长。命名参数不能使用此语法糖
- 适用于:全局函数、静态/实例成员函数、局部函数、构造函数、Lambda、函数调用运算符重载、索引运算符重载
- 不适用于:其他运算符重载、
~>、|> - 解析优先级:非变长匹配优先;仅当无非变长匹配时才尝试变长
Weekly Installs
3
Repository
kong-baiming/cangjie-devFirst Seen
3 days ago
Security Audits
Installed on
opencode2
gemini-cli2
claude-code2
github-copilot2
codex2
kimi-cli2