2.5. 临时类型

临时类型旨在解决数据的生命周期问题,这些问题直接从 C++ 公开给 Daslang。

让我们回顾一下下面的 C++ 示例:

void peek_das_string(const string & str, const TBlock<void,TTemporary<const char *>> & block, Context * context) {
    vec4f args[1];
    args[0] = cast<const char *>::from(str.c_str());
    context->invoke(block, args, nullptr);
}

此处的 C++ 函数公开了指向 c-string 的指针 a,位于 std::string 内部。 从 Daslang 的角度来看,函数的声明是这样的:

def peek ( str : das_string; blk : block<(arg:string#):void> )

其中 string# 是 Daslang 字符串类型的临时版本。

临时类型背后的主要思想是它们不能 “转义” 到它们所传递给的块的范围之外。

临时值通过遵循某些规则来实现此目的。

临时值无法复制或移动:

def sample ( var t : das_string ) {
    var s : string
    peek(t) $ ( boo : string# ) {
        s = boo // 错误,无法复制临时值
    }
}

临时值不能返回或传递给函数,这些函数需要常规值:

def accept_string(s:string)
    print("s={s}\n")

def sample ( var t : das_string )
    peek(t) $ ( boo : string# ) {
        accept_string(boo) // 错误
    }
}

这会导致以下错误:

30304: no matching functions or generics accept_string ( string const&# )
candidate function:
        accept_string ( s : string const ) : void
                invalid argument s. expecting string const, passing string const&#

值需要标记为 implicit 才能接受临时值和常规值。 这些函数隐式承诺不会以任何形式缓存 (复制、移动) 数据:

def accept_any_string(s:string implicit) {
    print("s={s}\n")
}

def sample ( var t : das_string ) {
    peek(t) $ ( boo : string# ) {
        accept_any_string(boo)
    }
}

临时值可以并且打算被克隆:

def sample ( var t : das_string ) {
    peek(t) $ ( boo : string# ) {
        var boo_clone : string := boo
        accept_string(boo_clone)
    }
}

返回临时值是不安全的作。

可以通过 safe_addr 宏接收相应范围的临时值的指针:

require daslib/safe_addr

def foo {
    var a = 13
    ...
    var b = safe_addr(a)    // b 是 int?#,并且此作不需要 unsafe
    ...
}