- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Horse
是一个实现 Animal
的结构特征。我有一个 Rc<Horse>
和一个需要接收 Rc<Animal>
的函数, 所以我想从 Rc<Horse>
转换至 Rc<Animal>
.
我这样做了:
use std::rc::Rc;
struct Horse;
trait Animal {}
impl Animal for Horse {}
fn main() {
let horse = Rc::new(Horse);
let animal = unsafe {
// Consume the Rc<Horse>
let ptr = Rc::into_raw(horse);
// Now it's an Rc<Animal> pointing to the same data!
Rc::<Animal>::from_raw(ptr)
};
}
这是一个好的解决方案吗?是否正确?
最佳答案
answer by Boiethios已经解释了可以使用 as
显式执行向上转换,甚至在某些情况下隐含地发生。我想补充一些有关机制的更多细节。
我将首先解释为什么您的不安全代码可以正常工作。
let animal = unsafe {
let ptr = Rc::into_raw(horse);
Rc::<Animal>::from_raw(ptr)
};
unsafe
中的第一行 block 消耗 horse
并返回 *const Horse
,这是一个指向具体类型的指针。指针正是您所期望的——horse
的内存地址。的数据(忽略在您的示例中 Horse
是零大小且没有数据的事实)。在第二行,我们调用Rc::from_raw()
;让我们看一下该函数的原型(prototype):
pub unsafe fn from_raw(ptr: *const T) -> Rc<T>
因为我们正在为 Rc::<Animal>
调用此函数,预期的参数类型是 *const Animal
.然而 ptr
我们有类型 *const Horse
,那么为什么编译器会接受代码呢?答案是编译器执行了一个unsized coercion,这是一种隐式类型转换,即performed in certain places for certain types。 .具体来说,我们将指向具体类型的指针转换为指向实现 Animal
的任何类型的指针。特征。由于我们不知道确切的类型,现在指针不再是单纯的内存地址——它是内存地址和对象实际类型的标识符,即所谓的胖指针。这样,Rc
从胖指针创建可以保留底层具体类型的信息,并且可以为Horse
调用正确的方法。 Animal
的实现(如果有的话;在你的例子中 Animal
没有任何功能,但当然如果有的话它应该继续工作)。
我们可以通过打印它们的大小来看出两种指针之间的区别
let ptr = Rc::into_raw(horse);
println!("{}", std::mem::size_of_val(&ptr));
let ptr: *const Animal = ptr;
println!("{}", std::mem::size_of_val(&ptr));
这段代码首先生成ptr
一个*const Horse
, 打印指针的大小,然后使用未指定大小的强制转换 ptr
和*const Animal
并再次打印它的大小。在 64 位系统上,这将打印
8
16
第一个只是一个简单的内存地址,而第二个是内存地址和指针对象的具体类型信息。 (具体来说,胖指针包含指向 virtual method table 的指针。)
现在让我们看看 Boethios 的回答中的代码发生了什么
let animal = horse as Rc<Animal>;
或等效
let animal: Rc<Animal> = horse;
还执行未定大小的强制转换。编译器如何知道如何为 Rc
执行此操作而不是原始指针?答案是 the trait CoerceUnsized
exists specifically for this purpose .您可以阅读 RFC on coercions for dynamically sized types了解更多详情。
关于将 Rc<ConcreteType> 转换为 Rc<Trait>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53276642/
Horse是一个实现 Animal 的结构特征。我有一个 Rc和一个需要接收 Rc 的函数, 所以我想从 Rc 转换至 Rc . 我这样做了: use std::rc::Rc; struct Hors
我有一个具体类,其中包含另一个具体类的集合。我想通过接口(interface)公开这两个类,但我无法弄清楚如何将 Collection 成员公开为 Collection 成员。 我目前使用的是 .NE
我正在尝试转换 Rc>至 Rc> ( Data 实现 Interface )但在通用方法中是不可能的: use std::cell::RefCell; use std::rc::Rc; trait I
我是一名优秀的程序员,十分优秀!