首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我如何转换从A &mut T到A &mut U型?

我如何转换从A &mut T到A &mut U型?
EN

Stack Overflow用户
提问于 2019-03-15 05:38:05
回答 3查看 810关注 0票数 2

我在试着理解借阅支票。我有一个有签名的函数

代码语言:javascript
复制
fn SerializeChar(&mut self, value: &mut u8)

我想从u8i8获得数据,因为我不关心标牌:

代码语言:javascript
复制
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)的事情,而借用检查器是可以的。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-03-15 12:31:12

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

是否有任何安全或不安全的方法将test作为参数传递给SerializeChar,类似于C++中的强制转换?

通过原始指针

按以下顺序转换:

  1. &mut i8
  2. *mut i8
  3. *mut u8
  4. &mut u8
代码语言:javascript
复制
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转换序列相比,这允许您做各种各样的坏事,并且在有其他选择时不受欢迎:

代码语言:javascript
复制
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所示。

尽管如此,这并不意味着没有更好的方法来完成你的目标。作为兰尼,您可以为有趣的类型创建一个特性,并隐藏实现内部的不安全代码。这使您的用户可以避免不安全。

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

也许还有更高层次的方法来解决你真正的问题。为什么你必须在这里对数据进行变异?这似乎是非常不寻常的序列化。

票数 3
EN

Stack Overflow用户

发布于 2019-03-15 12:37:55

你不能安全地这么做。一旦您有了&mutu8的引用,使用它的代码只能将其视为一个u8,您需要一些不安全的代码来进行转换。

as可以处理原始数值,因为它在内存中复制数据,并且可以处理此时的任何转换。这将不适用于引用,因为它无法更改原始值。

如果您绝对不能更改thing.serialize_char的签名,并且不能更改test变量的类型,那么解决方法是使用另一个变量,然后更新原始变量:

代码语言:javascript
复制
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需要比函数调用更长的引用时间,这是行不通的--但是如果是这样的话,借用检查器很快就会通知您!

票数 3
EN

Stack Overflow用户

发布于 2019-03-15 10:02:16

锈蚀中的特征可以是通用的,因此您可以定义具有以下签名的特征:

代码语言:javascript
复制
trait SerializeChar<T> {
    fn serialize_char(&mut self, value: &mut T);
}

然后用T = u8T = i8为您的结构实现它:

代码语言:javascript
复制
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; }
}

测试:

代码语言:javascript
复制
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);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55176192

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档