- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在为通用接口(interface)编写回调时,定义他们自己负责创建和访问的本地数据可能很有用。
在 C 中,我只使用一个空指针,类 C 示例:
struct SomeTool {
int type;
void *custom_data;
};
void invoke(SomeTool *tool) {
StructOnlyForThisTool *data = malloc(sizeof(*data));
/* ... fill in the data ... */
tool.custom_data = custom_data;
}
void execute(SomeTool *tool) {
StructOnlyForThisTool *data = tool.custom_data;
if (data.foo_bar) { /* do something */ }
}
当用 Rust 编写类似的东西时,替换 void *
与 Option<Box<Any>>
,但是我发现访问数据过于冗长,例如:
struct SomeTool {
type: i32,
custom_data: Option<Box<Any>>,
};
fn invoke(tool: &mut SomeTool) {
let data = StructOnlyForThisTool { /* my custom data */ }
/* ... fill in the data ... */
tool.custom_data = Some(Box::new(custom_data));
}
fn execute(tool: &mut SomeTool) {
let data = tool.custom_data.as_ref().unwrap().downcast_ref::<StructOnlyForThisTool>().unwrap();
if data.foo_bar { /* do something */ }
}
这里有一行我希望能够以更紧凑的方式编写:
tool.custom_data.as_ref().unwrap().downcast_ref::<StructOnlyForThisTool>().unwrap()
tool.custom_data.as_ref().unwrap().downcast_mut::<StructOnlyForThisTool>().unwrap()
虽然每个方法本身都有意义,但在实践中,我不想在整个代码库中编写它,也不是我想要经常输入或容易记住的东西。
按照惯例,在这里使用 unwrap 并不危险,因为:
鉴于这些约定,并假设从工具访问自定义数据是经常做的事情 - 什么是简化此表达式的好方法?
一些可能的选择:
Option
, 只需使用 Box<Any>
与 Box::new(())
代表None
因此可以稍微简化访问。Option<Box<Any>>
:当然可以,但最好不要 - 将作为最后的手段使用。Option<Box<Any>>
它公开了一个方法,例如 tool.custom_data.unwrap_box::<StructOnlyForThisTool>()
与匹配 unwrap_box_mut
.更新 1):自问这个问题以来,我没有包括的一点似乎是相关的。可能有多个回调函数,如 execute
这必须都能够访问 custom_data
.当时我认为指出这一点并不重要。
更新 2):将其包装在一个接受 tool
的函数中这是不切实际的,因为借用检查器会阻止进一步访问 tool
的成员在强制转换变量超出范围之前,我发现唯一可靠的方法是编写一个宏。
最佳答案
如果实现实际上只有一个名称类似于execute
的方法,则强烈表明要考虑使用闭包来捕获实现数据。 SomeTool
可以使用盒装的 FnMut
以类型删除的方式合并任意可调用对象,如图所示 in this answer . execute()
然后归结为使用 (self.impl_)()
调用存储在结构字段实现闭包中的闭包。对于更通用的方法,当您有更多的实现方法时,它也将起作用,请继续阅读。
type+dataptr C 模式的一种惯用且类型安全的等价物是将实现类型和指向数据的指针一起存储为 trait object。 . SomeTool
结构可以包含一个字段,一个装箱的 SomeToolImpl
特征对象,其中特征指定特定于工具的方法,例如 execute
。这具有以下特点:
您不再需要显式的 type
字段,因为运行时类型信息已包含在特征对象中。
特征方法的每个工具实现都可以以类型安全的方式访问自己的数据,无需转换或展开。这是因为 trait 对象的 vtable 会自动为正确的 trait 实现调用正确的函数,而尝试调用不同的函数是编译时错误。
trait 对象的“胖指针”表示与 type+dataptr 对具有相同的性能特征 - 例如,SomeTool
的大小将是两个指针,并且访问实现数据仍将涉及单个指针取消引用。
这是一个示例实现:
struct SomeTool {
impl_: Box<SomeToolImpl>,
}
impl SomeTool {
fn execute(&mut self) {
self.impl_.execute();
}
}
trait SomeToolImpl {
fn execute(&mut self);
}
struct SpecificTool1 {
foo_bar: bool
}
impl SpecificTool1 {
pub fn new(foo_bar: bool) -> SomeTool {
let my_data = SpecificTool1 { foo_bar: foo_bar };
SomeTool { impl_: Box::new(my_data) }
}
}
impl SomeToolImpl for SpecificTool1 {
fn execute(&mut self) {
println!("I am {}", self.foo_bar);
}
}
struct SpecificTool2 {
num: u64
}
impl SpecificTool2 {
pub fn new(num: u64) -> SomeTool {
let my_data = SpecificTool2 { num: num };
SomeTool { impl_: Box::new(my_data) }
}
}
impl SomeToolImpl for SpecificTool2 {
fn execute(&mut self) {
println!("I am {}", self.num);
}
}
pub fn main() {
let mut tool1: SomeTool = SpecificTool1::new(true);
let mut tool2: SomeTool = SpecificTool2::new(42);
tool1.execute();
tool2.execute();
}
请注意,在此设计中,将实现作为选项
没有意义,因为我们始终将工具类型 与实现相关联。虽然实现没有数据是完全有效的,但它必须始终具有与其关联的类型。
关于rust - 方便 'Option<Box<Any>>' 访问就一定成功?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41156227/
考虑这样的代码: trait Foo { fn foo(&self); } fn consume_func(b: Box>) { unimplemented!(); } fn prod
考虑这样的代码: trait Foo { fn foo(&self); } fn consume_func(b: Box>) { unimplemented!(); } fn prod
我不明白在 Rust 中,当我们 Box 父结构时,结构中的结构发生了什么。 struct Outer1 { child: Inner1, } struct Inner1 { n: i
我将开始开发一个新网站,并准备处理浏览器用于计算元素宽度和高度的不同方法 (box model stuff)。不知何故,我想到了:如果我只是将 box-sizing 应用于网站中的所有元素会怎么样?
在 java 应用程序中使用 box java sdk 访问 box api 时,我遇到了下面提到的错误。请指出此问题的原因。 Exception in thread "main" com.box.s
计算盒子的宽高时,outline width like outline: 5px dashed red; 如果 box-sizing:border-box,框的宽度/高度是否会考虑轮廓? 最佳答案 我
读完the subtyping chapter of the Nomicon ,我无法理解类型参数的协方差。特别是对于 Box类型,描述为:T is covariant . 但是,如果我写这段代码:
给定这段代码: trait Trait {} struct Child; impl Trait for Child {} struct Father { child: &'a Box, } i
与文件 chooser for dropbox 类似,box.com 有没有? 最佳答案 Box 目前不维护自己的“文件选择器”;然而,有一个很棒的服务叫做 filepicker.io,它充当几乎所有
感谢您对我的问题的回复:Is this a bug of Box API v2 when getting events 这是一个与此相关的新问题。问题是我不能可靠地使用从以前的调用中获得的 next_
我试图让 Box Enterprise API 使用 As-User 工作。我有一个管理员帐户,我用它来尝试检索子帐户中的内容。 我首先使用管理员帐户检索子帐户的用户ID。并将用户 ID 添加为字段“
我想在一个简单的导轨中本地查看我的 Box 帐户中的图像 app .目标是使用这些图像进行幻灯片放映。我寻找必要的参数来传递每个图像相关 url成标签。看来我只能下载图像,或从 Box 应用程序中查看
这个问题在这里已经有了答案: Why doesn't Rust support trait object upcasting? (5 个答案) 关闭 4 年前。 给定代码 trait Base {
所以基本上我尝试从https://github.com/Gor-Ren/gym-jsbsim转换这个自定义健身房环境。使用farama基金会的gymnasium api。这是我正在处理的存储库:htt
我是BOX API的新手,因此正在使用API的v2。我正在从我的应用程序本地进行REST调用。 我想上传一个以前可能上传或未上传的文件。我知道父文件夹ID和文件名。我需要覆盖现有文件,或者至少要再
我已被授予访问(协作)文件夹的权限。我需要的是每天访问该文件夹并从中获取文件。现在我生成的开发者 token 将在 1 小时后过期。有什么办法可以得到authorization code没有第一站,它
我正在尝试将 Box 中上传的文件与另一个外部系统同步。我使用哪些 API 来获取“在给定 dd/mm/yy hh:mm:ss 后上传/更新的所有文件的列表”? 干杯! 最佳答案 我认为User Ev
Vagrant 文档和 CLI 使用术语“box”和“base box”。命名意味着基本框是一种特定类型的框,但是,这些术语似乎被用作同义词。 Vagrant“盒子”和 Vagrant“基础盒子”之间
Box 允许您为文件夹创建标签,但如何从 API 中获取该信息?我在 GET /folders/{id} API 中没有看到标签返回.标签也不被视为元数据。 最佳答案 如果你看看 Fields wri
我正在尝试确定应该使用哪个版本的 Box api。我的决定取决于 v1 api 的 EOL 时间线。我不想完成我的应用程序,就在应用程序发布之前(或之后不久),v1 api 停止工作。 我很乐意使用
我是一名优秀的程序员,十分优秀!