如何从&mut T转换为&mut U类型?

问题描述 投票:1回答:3

我想了解借阅检查器。我有一个带签名的功能

fn SerializeChar(&mut self, value: &mut u8)

我想从u8i8获取数据,因为我不关心这个标志:

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)这样的借用检查器是可以的。

rust type-conversion
3个回答
3
投票

首先,这与借阅检查器无关。被告知一种类型与另一种类型不同是类型检查器的范围。

是否有任何安全或不安全的方法将test作为参数传递给SerializeChar,类似于在C ++中进行投射?

Via raw pointers

按此顺序转换:

  1. &mut i8
  2. *mut i8
  3. *mut u8
  4. &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
}

也可以看看:

Safety

所有通过as的演员都是安全的,虽然他们可能会产生虚假或意外的数据。

*mut u8转换为&mut u8或使用transmute是不安全的,因为程序员必须确保:

  • 维护参考规则
  • 值都具有其类型的有效值

我们知道该引用是有效的:仍然只有一个可变引用,它指向实时数据。

u8i8都适用于任何8位模式的位,即使语义值可能会发生变化,如u8::MAX如何变为-1所示。


所有这些都说,这并不意味着没有更好的方法来实现你的目标。作为Laney mentions,您可以为有趣的类型创建特征并隐藏实现内部的不安全代码。这样可以让您的用户避免不安全。

您还可以使用宏来创建多个类似的函数,而不必实际使用它们。

可能还有更高级别的方法来解决您的真实问题。为什么必须在这里改变数据?序列化似乎很不寻常。


3
投票

你不能安全地做到这一点。一旦你有一个&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需要比函数调用更长的时间,那么这将不起作用 - 但如果是这种情况,借用检查器很快就会让你知道!


1
投票

Rust中的特征可以是通用的,因此您可以使用以下特征定义特征:

trait SerializeChar<T> {
    fn serialize_char(&mut self, value: &mut T);
}

然后使用T = u8T = 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);
}
© www.soinside.com 2019 - 2024. All rights reserved.