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
...
}