2.8. Unsafe
unsafe
关键字表示不安全的内容,这是作所必需的,但可能会使应用程序崩溃:
unsafe {
let px = addr(x)
}
表达式(和子表达式)也可能是不安全的:
let px = unsafe(addr(x))
Unsafe 后跟一个可以包含这些作的块。允许嵌套的 unsafe 部分。在 lambda、generator 或本地函数中不会继承 Unsafe;但是,它是在本地块中继承的。
单个表达式可能会导致 CompilationError::unsafe 错误,除非它们是 unsafe 部分的一部分。此外,宏可以显式设置 ExprGenFlags::alwaysSafe 标志。
表达式的地址不安全:
unsafe {
let a : int
let pa = addr(a)
return pa // 访问 *PA 可能会损坏堆栈
}
lambda 或生成器需要不安全的部分才能通过 move 或 by reference 进行隐式捕获:
var a : array<int>
unsafe {
var counter <- @ (extra:int) : int {
return a[0] + extra // a 被隐式移动
}
}
删除任何指针都需要一个 unsafe 部分:
var p = new Foo()
var q = p
unsafe {
delete p // 访问 q 可能会损坏内存
}
Upcast 和 reinterpret cast 需要一个 unsafe 部分:
unsafe {
return reinterpret<void?> 13 // reinterpret 可以创建不安全的指针
}
索引到指针中是不安全的:
unsafe {
var p = new Foo()
return p[13] // 访问越界指针可能会损坏内存
}
如果 safe 索引后面没有 null 合并运算符,则 safe 索引是不安全的:
var a = { 13 => 12 }
unsafe {
var t = a?[13] ?? 1234 // safe
return a?[13] // unsafe; safe Index 是 'addr'作的一种形式
// 它可以创建指向临时对象的指针
}
如果 null 合并运算符后跟,则局部变量上的变体 ?as
是不安全的:
unsafe {
return a ?as Bar // 安全,就像 'addr'作的一种形式一样
}
变体 .?field
当后面没有 null 合并运算符时是不安全的:
unsafe {
return a?.Bar // 变体的安全导航是 'addr'作的一种形式
}
变体 .field
是 unsafe:
unsafe {
return a.Bar // 这可能是 reinterpret cast(重新解释的演员阵容)
}
某些函数和运算符本质上是不安全的,或者通过 [unsafe_operation] 注释标记为不安全:
unsafe {
var a : int?
a += 13 // 指针算术可以创建无效指针
var boo : int[13]
var it = each(boo) // 数组的 each() 是不安全的,因为它不会捕获
}
从智能指针值移动需要 unsafe,除非该值是 ‘new’ 运算符:
unsafe {
var a <- new TestObjectSmart() // safe, 它显然是新的
var b <- someSmartFunction() // unsafe 由于寿命不明显
b <- a // safe, 值不会丢失
}
移动或复制类是不安全的:
def foo ( var b : TestClass ) {
unsafe {
var a : TestClass
a <- b // 可能从派生类移动
}
}
局部类变量不安全:
unsafe {
var g = Goo() // 潜在的生命周期问题
}
2.9. implicit
implicit 关键字用于指定 type 可以是 临时 或 常规 类型,并将被视为已定义。 例如:
def foo ( a : Foo implicit ) // a 将被视为 Foo,但也接受 Foo# 作为参数
def foo ( a : Foo# implicit ) // a 将被视为 Foo#,但也接受 Foo 作为参数
不幸的是,像这样的隐式转换是不安全的,因此 implicit 根据定义是不安全的。
2.10. 其他情况
还有其他几种情况需要 unsafe,但文档中没有明确提到。 它们通常通过 CodeOfPolicies 或适当的选项进行控制:
options unsafe_table_lookup = false // 使表索引安全。见 CodeOfPolicies::unsafe_table_lookup
var tab <- { 1=>"one", 2=>"two" }
tab[3] = "three" // 这是不安全的,因为它可以创建指向临时对象的指针