你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

闭包

闭包是可捕获封闭环境中的变量的可调用项。 可以创建函数和运算闭包。 运算闭包可以在函数内创建,但只能在运算中应用。

Q# 有两种创建闭包的机制:Lambda 表达式和偏函数应用。

Lambda 表达式

Lambda 表达式创建匿名函数或运算。 基本语法是用于绑定参数的符号元组、箭头(对于函数是 ->,对于运算是 =>)和用于计算结果的表达式(应用时)。

// Function that captures 'x':
y -> x + y

// Operation that captures 'qubit':
deg => Rx(deg * PI() / 180.0, qubit)

// Function that captures nothing:
(x, y) -> x + y

参数

参数是使用与左侧变量声明语句相同的符号元组绑定的。 参数元组的类型是隐式的。 不支持类型注释;如果类型推理失败,可能需要创建顶级可调用声明并改用偏函数应用。

可变捕获变量

无法捕获可变变量。 如果只需在创建 Lambda 表达式时捕获可变变量的值,则可以创建不可变副本:

// ERROR: 'variable' cannot be captured.
mutable variable = 1;
let f = () -> variable;

// OK.
let value = variable;
let g = () -> value;

特征

匿名操作的特征是根据 lambda 的应用程序推断出来的。 如果 lambda 与函子应用程序一起使用,或在需要特征的上下文中,则推断 lambda 具有该特征。 例如:

operation NoOp(q : Qubit) : Unit is Adj {}
operation Main() : Unit {
    use q = Qubit();
    let foo = () => NoOp(q);
    foo(); // Has type Unit => Unit with no characteristics

    let bar = () => NoOp(q);
    Adjoint bar(); // Has type Unit => Unit is Adj
}

如果需要与推断的运算 lambda 不同的特征,则需要改为创建顶级运算声明。

偏函数应用

偏函数应用是一种便捷的方式,用于应用可调用项参数中的一些参数(但并非全部参数)。 语法与调用表达式相同,但未应用的参数会替换为 _。 从概念上讲,偏函数应用等效于捕获已应用参数并采用未应用的参数作为参数的 Lambda 表达式。

例如,假设 f 是一个函数,o 是一个运算,并且已捕获的变量 x 是不可变的:

偏函数应用 Lambda 表达式
f(x, _) a -> f(x, a)
o(x, _) a => o(x, a)
f(_, (1, _)) (a, b) -> f(a, (1, b))[^1]
f((_, _, x), (1, _)) ((a, b), c) -> f((a, b, x), (1, c))

可变捕获变量

与 Lambda 表达式不同,偏函数应用可以自动捕获可变变量值的副本:

mutable variable = 1;
let f = Foo(variable, _);

这等效于以下 Lambda 表达式:

mutable variable = 1;
let value = variable;
let f = x -> Foo(value, x);

[^1]:参数元组是严格编写的 (a, (b)),但 (b) 等效于 b