我想重新解释对可变引用的不可变引用(在不安全的块中,并独自负责安全检查,但看来我不能使用mem::transmute()
来这样做。
let map_of_vecs: HashMap<usize, Vec<_>> = ...;
let vec = map_of_vecs[2];
/// obtain a mutable reference to vec here
Vec
包装到Cell
中,因为这会影响使用map_of_vecs
的所有其他代码区域,而我只需要一行就可以更改。map_of_vecs
Rust优化器假设&mut T
引用是唯一的。例如,它可能推断出可以重用特定的一块内存,因为存在对该内存的可变引用,但是再也不会对其进行访问。
但是,如果将&T
转换为&mut T
,则可以为同一数据创建多个可变引用。如果编译器做出此假设,您最终可能会取消引用已经被其他内容覆盖的值。
这只是编译器可能如何利用可变引用是唯一的假设的一个示例。实际上,编译器可以自由使用它认为合适的任何方式使用此信息-可能(并且可能会)在版本之间进行更改。
即使您认为,您也已保证引用没有别名,您也不能始终保证您的代码用户不会创建更多引用。即使您认为可以肯定,引用的存在也非常微妙,很容易错过其中的一个。例如,当您调用采用&self
的方法时,这就是参考。
Rust编译器使用LLVM &T
和noalias
属性注释readonly
函数参数(前提是T
不包含任何UnsafeCell
部分)。 noalias
属性告诉LLVM,该指针后面的内存只能通过this指针(而不是通过任何其他指针)写入,而readonly
属性则告诉LLVM无法对其进行写入通过该指针(但可能还有其他指针)。结合使用,这两个属性允许LLVM优化器假定在执行此功能期间内存完全没有变化,并且可以基于此假设来优化代码。优化程序可能会重新排序指令或删除代码,只有在您确实遵守此合同的情况下,这种方法才可以安全地进行。
转换可能导致不确定行为的另一种方法是针对静态变量:没有UnsafeCell
的不可变静态变量将被放置到只读存储器中,因此,如果您实际写入它们,则代码将出现段错误。
对于具有UnsafeCell
的参数,编译器不会发出readonly
属性,而将包含UnsafeCell
的静态变量放入可写内存。