我正在尝试了解借阅检查器。我有一个带有签名
的函数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
的事情,借阅检查器还可以。
答案 0 :(得分:3)
首先,这与借阅检查器无关。被告知一种类型与另一种类型不同的是 type 检查器的权限。
是否有任何安全或不安全的方法将
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一样,您可以为有趣的类型创建特征,并隐藏实现内部的不安全代码。这样您的用户可以避免这种不安全的情况。
您也可以使用宏来创建多个相似的函数,而不必实际使它们相同。
也许还有更高层次的方法可以解决您的实际问题。为什么必须在此处更改数据?序列化似乎很不寻常。
答案 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 = 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);
}