跳到主要内容
版本:release

闭包

语法

  • ( : 可调用表达式1 (, 实参列表2)? : )

注释:

  1. 闭包支持如下形式的可调用表达式:
形式语法
1标识符
2类型 . 标识符
3表达式 ?? . | => ?? 标识符
  1. 实参列表的语法与 函数调用表达式 中的实参列表相同:

表达式 (, 表达式)*

描述

闭包表达式用于创建一个 function 实例。

闭包表达式的可调用表达式部分用于指定闭包实例所绑定的函数,可以是一个函数名(形式1), 也可以是一个类型拓展函数或对象的成员函数(形式2)。

闭包表达式中,被调用的函数不能是另一个 function 实例,它应当直接指向一个函数实体。如有需要,应该:

function f1 = ...;

// function f2 = (: f1 :); // Bad, f1 cannot be a `function` instance.
function f2 = (: f1.call :); // Ok

闭包表达式的实参列表部分用于指定闭包实例所绑定函数的实参,相当于预先传入了这些实参。如果被调用的函数能在 编译期确定,则传入实参时会进行类型检查(不会在编译期检查参数数量);如果传入的实参与形参类型不匹配,则会 导致编译错误。

如果无法在编译期检查,对于实参的参数类型检查将被推迟到运行时进行,参见 函数调用表达式

当尝试调用一个 object 的方法时,对象实例将被一同打入 function 中;如果方法不是 parallel 的,那么函数会自动带上目标对象所 在的域作为参数域。

如果闭包传入了 引用容器类型 的实参,则在闭包调用时,传入的实参会被解引用。

如果目标函数是一个对象的方法,无论该对象属于什么域,也无论目标方法是否 parallel,都可以使用 .=>(形式3)。 如果要调用当前对象的方法,可以省略指示对象的表达式(形式1)。

为了确保函数能被在正确的域上调用,闭包表达式创建的 function 实例可能会带有参数域;对于有参数域的 function 实例, 在调用时会跨入目标域,参见下表以确定闭包会在何时带上参数域:

影响参数域的因素导致的行为
尝试调用对象的非 parallel 方法带上对象的域作为参数域
传入了 RW 的实参带上当前域作为参数域

需要特别注意的是: 可以注意到,对象的域与当前域可能并不相同;如果因为对象方法本身已经引入了非当前域的参数域,除非使 用 => 指示,否则不允许传入 RW 的实参。

当指示了 => 时,传入的 RW 的引用容器类 型实参将被 复制function 的参数域上,哪怕函数的参数域与当期域一致:

object obj = new_object(Example, domain.create());
function f1 = (: obj.parallel_method :); // Ok, 目标函数是 parallel 方法,f1 没有参数域
function f2 = (: obj.parallel_method, {} :); // Ok, 目标函数是 parallel 方法,因为传入了 RW 的引用容器作为实参,f2 的参数域为当前域
function f3 = (: obj=>parallel_method, 1 :); // Ok, 尽管指示了 `=>`,但是 f3 没有参数域,因为目标函数是 parallel 方法
function f4 = (: obj=>parallel_method, {} :); // Ok, 因为目标函数是 parallel 方法,且指示了 `=>`,参数在当前域被复制,f4 的参数域是当期域

function f5 = (: obj.non_parallel_method :); // Ok, 目标函数是非 parallel 方法,f5 的参数域为 obj 的域
function f6 = (: obj.non_parallel_method, 1, make_parallel({}) :); // Ok, 目标函数是非 parallel 方法,传入的实参不包含 RW 的引用容器,f6 的参数域为 obj 的域
// function f7 = (: obj.non_parallel_method, {} :); // Bad, 目标函数是非 parallel 方法,传入了 RW 的引用容器作为实参,这不被允许
function f8 = (: obj=>non_parallel_method, {} :); // Ok, 使用了 `=>` 指示,传入 RW 的引用容器作为实参,f8 的参数域为 obj 的域,参数被复制到 obj 的域

如果没有影响参数域的因素,function 实例不会带上参数域;没有参数域的 function 实例可以在任何域上调用。

如果在创建闭包时指定的实参数量少于函数的(必填)形参数量,则在调用闭包实例时,应当传入剩余的实参。确保 function 实例在被实际调用时,传入的实参数量与函数的形参匹配。

示例

void debug_print(string a, int b, float c) {
writeln(a, ": ", b, ", ", c);
}

function f = (: debug_print : "Value", 42);
f.call(3.14); // 输出 "Value: 42, 3.14"
(*f)(3.14); // 也可以这么做

// (: f :) // Bad, f cannot be a `function` instance.
// (: *f :) // Bad
(: f.call :) // Ok