2.15.

块是无名函数,它通过引用捕获本地上下文。 与 lambda 相比,数据块具有显著的性能优势 (参阅 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")
}

类似类型的块通常通过 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
    }
}

块注释可以通过适当的宏来实现 (参阅 Macro).

允许使用局部块变量:

var blk = $ ( a, b : int ) {
    return a + b
}
verify ( 3 == invoke(blk,1,2) )
verify ( 7 == invoke(blk,3,4) )

它们不能被复制或移动。