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"        // 这是不安全的,因为它可以创建指向临时对象的指针