Skip to Content

函数(Function)

func 声明函数。返回注解可省,省略即 void;需要返回值时必须写 -> T,return 的类型严格对照声明。

基本形态

func Add(a: int, b: int) -> int { return a + b; } func Dbl(n: int) -> int => n * 2; func Fib(n: int) -> int { if n < 2 { return n; } return Fib(n - 1) + Fib(n - 2); }
  • 表达式体 => expr; 是单表达式函数的紧凑写法,语义与块体一致。
  • 递归直接写名字调用,上面的 Fib(10) 得 55。
  • 语句块的返回类型检查是双向严格的:声明 -> int 却漏 return、或 return 类型不符,均无法通过编译。

参数修饰

形参首列修饰符决定传递方式:

修饰名字语义
(无)默认同 val 不可变传递
val不可变传递形参体内不可赋值
var可变传递形参是实参的副本,体内可改,不影响调用方
in只读传递只读视图,适合大对象免拷
ref可写回形参与实参同一存储,体内的写回对实参生效
out仅写回进函数时不需要值,专门用于带回结果
params变参末位形参收任意个实参,体内是数组

ref 与 out 的调用位要显式写修饰符:

func Swap(ref a: int, ref b: int) { val t = a; a = b; b = t; } func Divide(a: int, b: int, out remainder: int) -> int { remainder = a % b; return a / b; } var x = 1; var y = 2; Swap(ref x, ref y); print(x, y); var rem = 0; print(Divide(7, 2, out rem), rem);
2 1 3 1

Swap(ref x, ref y) 调用后 x、y 已交换;Divide(7, 2, out rem) 返回商 3,rem 带回余数 1。

默认参数

参数可以带默认值,值必须是编译期常量。默认值参数调用时可省:

func Greet(name: string, greeting: string = "你好", punct: string = "!") -> string { return $"{greeting},{name}{punct}"; } print(Greet("世界")); print(Greet("世界", "早上好"));
你好,世界! 早上好,世界!

命名实参

实参可以写成 名: 值,按名绑定形参槽:可乱序、可跳过有默认值的参数,位置实参要放在命名实参之前:

print(Greet("世界", punct: "。")); print(Greet(greeting: "晚安", name: "月亮"));
你好,世界。 晚安,月亮!

params 与展开调用

params 修饰末位形参,实参个数任意,体内是一个长度固定的数组。要把一个集合整体交给 params 形参,用展开调用:实参列表写成 ... 加集合名,集合逐元素摊开:

func Total(params nums: int[]) -> int { var total = 0; for n in nums { total += n; } return total; } val xs: list<int> = [4, 5]; print(Total(1, 2, 3)); print(Total(...xs)); print(Total(1, ...xs));
6 9 10

Total(...xs) 把列表逐元素展开,等价 Total(4, 5);字面量同样能展开(Total(...[7, 8]))。

展开实参不必独占实参列表。params 调用的位实参表就是 params 数组的字面量构形,与列表字面量 [1, ...xs] 同构:...xs 在哪个位置,元素就摊进数组的哪个位置——Total(1, ...xs) 直写合法,等价 Total(1, 4, 5);展开可以放在中间、也可以多个(Total(...a, 2, ...b)),集合元素类型要对照 params 的元素类型:

val head: list<int> = [1, 2]; val tail: list<int> = [8, 9]; print(Total(...head, 5, ...tail));
25

固定形参优先吃位实参:位实参先按声明顺序填固定形参,溢出的和展开的一起进 params 数组。展开后面的位实参照旧按声明序吃固定槽——Join(...xs, "a") 里 "a" 是第一个位实参,填的是 sep:

func Join(sep: string, params items: int[]) -> string { var s = ""; var first = true; for n in items { if (!first) { s = s + sep; } s = s + n.ToString(); first = false; } return s; } val xs: list<int> = [4, 5]; print(Join(";", 1, ...xs)); print(Join(...xs, "a"));
1;4;5 4a5

命名实参永不摊开:按名绑定自己的形参槽,位实参与展开的照常展平——Join(sep: "-", ...xs) 的 xs 照样摊进 items。每个实参按源码顺序恰求值一次。

重载

同名函数构成重载集,调用按实参类型解析,取最佳匹配:

func Show(v: int) -> string => $"int {v}"; func Show(v: string) -> string => $"string {v}"; print(Show(7), Show("七"));
int 7 string 七

消歧按评分层级(精确 > 可赋值 > 提升 > 装箱),省略尾参少者优先,定元形优先于 params 展开。

泛型与 where

类型参数写在名字后,约束用 where 子句。子句顺序固定:uses → fail → where,然后才是 ->:

import Math.*; func Bigger<T>(a: T, b: T) where T: Ordered -> T { if a < b { return b; } return a; } print(Bigger(4, 9));
9

Ordered 是 std Math 提供的协议(含序比较),内建标量隐式满足,泛型体内的 a < b 按约束协议的运算符签名放行。协议名在类型位裸名书写需要 import Math.*; 激活。

具名函数作值

函数名出现在值位(实参、赋值、返回、装容器)时物化为函数值,类型是函数类型:

func On(n: int) -> void => print("on", n); val f: func(int) -> void = On; f(4); val g = On; g(5);
on 4 on 5

同声明的函数物化成同一个值(单例);lambda 则每次求值都是新实例,见 lambda 与闭包。== 按这个实例身份判:同单例恒等,不同实例不等,见判等与哈希。

注意

  • 顶层 func 是模块成员,可见性由模块系统管理,见组织代码部分;类型成员方法带 self 接收者,见类型部分。
  • async func 见异步部分,本文不过多赘述。
最后更新于 2026年10月9日