我想了解借阅检查器。我有一个带签名的功能
fn SerializeChar(&mut self, value: &mut u8)
我想从u8
和i8
获取数据,因为我不关心这个标志:
let mut test: i8 = 0;
thing.SerializeChar(&mut test); //Error: &mut u8 expected
那没关系,但我究竟该怎么做呢?
&mut (test as u8)
不是一回事。是否有任何安全或不安全的方法将测试作为参数传递给SerializeChar
,类似于在C ++中进行投射?当我这样做时,我也不想破坏test
,因为我仍然需要test
,并且仍然希望它作为i8
,而不是u8
。
我不是想克隆价值。我想要地址为test
,因为SerializeChar
中的数据是可变的,需要修改放入的内容。在C ++术语中我不想要char
,我想要一个*char
,因为我需要在内存中修改8位。有可能我可以做两个单独版本的SerializeChar
,但在此之前我想知道是否有可能真正做像*u8(test)
这样的借用检查器是可以的。
首先,这与借阅检查器无关。被告知一种类型与另一种类型不同是类型检查器的范围。
是否有任何安全或不安全的方法将
test
作为参数传递给SerializeChar
,类似于在C ++中进行投射?
按此顺序转换:
&mut i8
*mut i8
*mut u8
&mut u8
fn serialize_char(value: &mut u8) {
*value = std::u8::MAX
}
fn main() {
let mut test: i8 = 0;
serialize_char(unsafe { &mut *(&mut test as *mut i8 as *mut u8) });
println!("{}", test); // -1
}
也可以看看:
transmute
使用as
应该永远是你的第一次尝试,但也有transmute
的大锤子。与简单的as
演员序列相比,这可以让你做各种不好的事情,当有另一种选择时,它不受欢迎:
use std::mem;
fn serialize_char(value: &mut u8) {
*value = std::u8::MAX
}
fn main() {
let mut test: i8 = 0;
serialize_char(unsafe { mem::transmute(&mut test) });
println!("{}", test); // -1
}
也可以看看:
所有通过as
的演员都是安全的,虽然他们可能会产生虚假或意外的数据。
从*mut u8
转换为&mut u8
或使用transmute
是不安全的,因为程序员必须确保:
我们知道该引用是有效的:仍然只有一个可变引用,它指向实时数据。
u8
和i8
都适用于任何8位模式的位,即使语义值可能会发生变化,如u8::MAX
如何变为-1
所示。
所有这些都说,这并不意味着没有更好的方法来实现你的目标。作为Laney mentions,您可以为有趣的类型创建特征并隐藏实现内部的不安全代码。这样可以让您的用户避免不安全。
您还可以使用宏来创建多个类似的函数,而不必实际使用它们。
可能还有更高级别的方法来解决您的真实问题。为什么必须在这里改变数据?序列化似乎很不寻常。
你不能安全地做到这一点。一旦你有一个&mut
引用u8
,使用它的代码只能将它视为u8
,你需要一些不安全的代码来进行转换。
as
使用原始数值,因为它将数据复制到内存中,并且它可以处理该点的任何转换。这不适用于引用,因为它无法更改原始值。
如果您绝对无法更改thing.serialize_char
的签名,并且您无法更改test
变量的类型,则解决方法是使用另一个变量然后更新原始:
let mut test: i8 = 0;
let mut test_u8 = test as u8;
thing.serialize_char(&mut test_u8);
test = test_u8 as i8;
如果serialize_char
需要比函数调用更长的时间,那么这将不起作用 - 但如果是这种情况,借用检查器很快就会让你知道!
Rust中的特征可以是通用的,因此您可以使用以下特征定义特征:
trait SerializeChar<T> {
fn serialize_char(&mut self, value: &mut T);
}
然后使用T = u8
和T = i8
为您的结构实现它:
struct Thing {}
impl SerializeChar<u8> for Thing {
fn serialize_char(&mut self, value: &mut u8) { *value = 55; }
}
impl SerializeChar<i8> for Thing {
fn serialize_char(&mut self, value: &mut i8) { *value = 56; }
}
测试:
fn main() {
let mut a = 0u8;
let mut b = 0i8;
let mut thing = Thing{};
thing.serialize_char(&mut a);
thing.serialize_char(&mut b);
dbg!(a);
dbg!(b);
}