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

时间:2019-03-15 05:38:05

标签: rust type-conversion

我正在尝试了解借阅检查器。我有一个带有签名

的函数
import pandas as pd

wavelengths= [400, 401,402]
cols = ['prong', 'scan'] + wavelengths 

df1 = pd.concat([pd.DataFrame(dict([(k, pd.Series(v)) for k, v in d.items()])) for d in data])
df1 = df1.reset_index(drop=True).ffill()
df2 = pd.DataFrame([(x,y,*z) for x,y,z in df1['responses']], columns= cols)

df = pd.concat([df1.drop('responses', 1), df2], 1)
# Separate dataset
         date  measurement  prong  scan  400  401  402
0  2018-01-01        100.0      1     1    1    2    3
1  2018-01-01        100.0      2     1    4    5    6
2  2018-01-02        200.0      3     1    5    6    7
3  2018-01-02        200.0      4     1    8    9   10

df.groupby(['date', 'measurement'])[wavelengths].mean().reset_index()
# Average dataset
         date  measurement  400  401  402
0  2018-01-01        100.0  2.5  3.5  4.5
1  2018-01-02        200.0  6.5  7.5  8.5

我想从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)的参数传递,就像在C ++中一样?另外,我不想销毁SerializeChar,因为我仍然需要test,并且仍然希望将其作为test,而不是i8

我不是要克隆值。我希望地址为u8,因为test中的数据是可变的,并且需要修改放入的内容。用C ++术语,我不需要SerializeChar,我想要{{ 1}},因为我需要修改内存中的8位。有可能我可以做两个char的单独版本,但是在此之前,我想知道是否真的可以做类似*char的事情,借阅检查器还可以。

3 个答案:

答案 0 :(得分:3)

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

  

是否有任何安全或不安全的方法将test作为SerializeChar的参数传递,就像在C ++中一样?

通过原始指针

按以下顺序进行转换:

  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
}

另请参阅:

安全

通过as进行的所有强制类型转换都是安全的,尽管它们可能会产生假数据或意外数据。

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

  • 维护引用规则
  • 这些值的类型均具有有效值

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

u8i8都对任何8位位模式都有效,即使语义值可能会发生变化,如u8::MAX变为{{1}所示}。


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

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

也许还有更高层次的方法可以解决您的实际问题。为什么必须在此处更改数据?序列化似乎很不寻常。

答案 1 :(得分:3)

您不能安全地执行此操作。一旦拥有对&mut的{​​{1}}引用,使用它的代码只能将其视为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; 需要引用的时间比函数调用的时间长,则此方法将不起作用-但如果是这种情况,借用检查器将很快让您知道!

答案 2 :(得分: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);
}