.. _blocks: ===== 块 ===== 块是无名函数,它通过引用捕获本地上下文。 与 lambda 相比,数据块具有显著的性能优势 (参阅 :ref:`Lambda `). 块类型可以使用类似函数的语法来声明:: block_type ::= block { optional_block_type } optional_block_type ::= < { optional_block_arguments } { : return_type } > optional_block_arguments := ( block_argument_list ) block_argument_list := argument_name : type | block_argument_list , argument_name : type block < (arg1:int;arg2:float&):bool > 块捕获当前堆栈,因此可以传递块,但永远不会返回。 块变量只能作为参数传递。 禁止使用全局或局部块变量;也禁止返回 block 类型:: def goo ( b : block ) ... def foo ( b : block < (arg1:int, arg2:float&) : bool > ... 区块可以通过 ``invoke`` 调用:: def radd(var ext:int&;b:block<(var arg:int&):int>):int { return invoke(b,ext) } 还有一个简写,其中 block 可以像函数一样调用:: def radd(var ext:int&;b:block<(var arg:int&):int>):int { return b(ext) // same as invoke(b,ext) } 无类型块通常通过类似构造的语法声明:: goo() { // 不带参数的块 print("inside goo") } .. _blocks_declarations: 类似类型的块通常通过 pipe 语法声明:: var v1 = 1 // 带参数的块 res = radd(v1) <| $(var a:int&):int { return a++ } 块也可以通过内联语法声明:: res = radd(v1, $(var a:int&) : int { return a++; }) // 等同于上面的例子 对于仅包含返回表达式的块,有一个简化的语法:: res = radd(v1, $(var a:int&) : int => a++ ) // 等同于上面的例子 如果在泛型 或 函数中充分指定了块,则将自动推断块类型:: res = radd(v1, $(a) => a++ ) // 等同于上面的例子 允许嵌套块:: def passthroughFoo(a:Foo; blk:block<(b:Foo):void>) { invoke(blk,a) } passthrough(1) <| $ ( a ) { assert(a==1) passthrough(2) <| $ ( b ) { assert(a==1 && b==2) passthrough(3) <| $ ( c ) { assert(a==1 && b==2 && c==3) } } } 不允许循环控制表达式跨越块边界:: while ( true ) { take_any() { break // 30801,捕获的块不能在块外突破 } } 块可以有注释:: def queryOne(dt:float=1.0f) { testProfile::queryEs() <| $ [es] (var pos:float3&;vel:float3 const) { // [es] 是注解 pos += vel * dt } } 块注释可以通过适当的宏来实现 (参阅 :ref:`Macro `). 允许使用局部块变量:: var blk = $ ( a, b : int ) { return a + b } verify ( 3 == invoke(blk,1,2) ) verify ( 7 == invoke(blk,3,4) ) 它们不能被复制或移动。