- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在 C/C++ 中,我通常会使用普通函数指针进行回调,可能会传递一个 void* userdata
参数也是。像这样的东西:
typedef void (*Callback)();
class Processor
{
public:
void setCallback(Callback c)
{
mCallback = c;
}
void processEvents()
{
for (...)
{
...
mCallback();
}
}
private:
Callback mCallback;
};
setCallback()
函数取什么类型,应该是什么类型
mCallback
是?是否需要一个
Fn
?也许
FnMut
?我要保存吗
Boxed
?一个例子将是惊人的。
最佳答案
简短回答:为了获得最大的灵活性,您可以将回调存储为盒装 FnMut
对象,在回调类型上具有通用的回调 setter 。答案的最后一个示例中显示了此代码。有关更详细的解释,请继续阅读。
“函数指针”:回调为 fn
问题中与 C++ 代码最接近的等价物是将回调声明为 fn
类型。 fn
封装了 fn
定义的函数关键字,很像 C++ 的函数指针:
type Callback = fn();
struct Processor {
callback: Callback,
}
impl Processor {
fn set_callback(&mut self, c: Callback) {
self.callback = c;
}
fn process_events(&self) {
(self.callback)();
}
}
fn simple_callback() {
println!("hello world!");
}
fn main() {
let p = Processor {
callback: simple_callback,
};
p.process_events(); // hello world!
}
此代码可以扩展为包含
Option<Box<Any>>
保存与该功能相关的“用户数据”。即便如此,它也不是惯用的 Rust。 Rust 将数据与函数关联的方法是在匿名闭包中捕获它,就像在现代 C++ 中一样。由于闭包不是
fn
,
set_callback
将需要接受其他类型的函数对象。
callback
的类型。字段,也不能使用别名。
struct Processor<CB>
where
CB: FnMut(),
{
callback: CB,
}
impl<CB> Processor<CB>
where
CB: FnMut(),
{
fn set_callback(&mut self, c: CB) {
self.callback = c;
}
fn process_events(&mut self) {
(self.callback)();
}
}
fn main() {
let s = "world!".to_string();
let callback = || println!("hello {}", s);
let mut p = Processor { callback: callback };
p.process_events();
}
和以前一样,回调的新定义将能够接受用
fn
定义的顶级函数。 ,但这个也将接受闭包
|| println!("hello world!")
,以及捕获值的闭包,例如
|| println!("{}", somevar)
.因此,处理器不需要
userdata
陪伴回调;
set_callback
的调用者提供的闭包将自动从其环境中捕获所需的数据,并在调用时使其可用。
FnMut
怎么办? ,为什么不只是
Fn
?由于闭包保存了捕获的值,因此在调用闭包时必须应用 Rust 的通常变异规则。根据闭包对它们所持有的值的作用,它们被分为三个系列,每个系列都标有一个特征:
Fn
是只读取数据的闭包,可以安全地多次调用,可能来自多个线程。以上两个闭包都是Fn
. FnMut
是修改数据的闭包,例如通过写入捕获的 mut
变量。它们也可能被多次调用,但不能并行调用。 (从多个线程调用 FnMut
闭包会导致数据竞争,因此只能通过互斥锁的保护来完成。)闭包对象必须由调用者声明为可变的。 FnOnce
是消耗它们捕获的一些数据的闭包,例如通过将捕获的值传递给按值获取它的函数。顾名思义,这些只能被调用一次,并且调用者必须拥有它们。 FnOnce
实际上是最宽容的。声明通用回调类型必须满足
FnOnce
trait 意味着它将接受任何闭包。但这是有代价的:这意味着持有者只能调用一次。自
process_events()
可以选择多次调用回调,并且由于方法本身可能被多次调用,下一个最宽松的界限是
FnMut
.请注意,我们必须标记
process_events
作为变异
self
.
Processor
使用具体回调类型参数化的实例,这意味着单个
Processor
只能处理单一的回调类型。鉴于每个闭包都有不同的类型,泛型
Processor
无法处理
proc.set_callback(|| println!("hello"))
其次是
proc.set_callback(|| println!("world"))
.扩展结构以支持两个回调字段需要将整个结构参数化为两种类型,随着回调数量的增加,这将很快变得笨拙。如果回调的数量需要是动态的,例如,添加更多类型参数将不起作用。实现
add_callback
维护不同回调向量的函数。
Fn
的闭包之间的区别。和一个
Fn
trait 对象等同于一般函数对象和
std::function
的区别C++ 中的值。
&
的对象来创建 trait 对象。运算符并将其强制转换为对特定特征的引用。在这种情况下,由于
Processor
需要拥有回调对象,我们不能使用借用,但必须将回调存储在堆分配中
Box<dyn Trait>
(Rust 等效于
std::unique_ptr
),它在功能上等效于特征对象。
Processor
专卖店
Box<dyn FnMut()>
,它不再需要是通用的,而是
set_callback
方法现在接受泛型
c
通过
impl Trait
argument .因此,它可以接受任何类型的可调用对象,包括带状态的闭包,并在将其存储在
Processor
之前将其正确装箱。 .
set_callback
的通用参数不限制处理器接受什么样的回调,因为接受回调的类型与存储在
Processor
中的类型分离。结构。
struct Processor {
callback: Box<dyn FnMut()>,
}
impl Processor {
fn set_callback(&mut self, c: impl FnMut() + 'static) {
self.callback = Box::new(c);
}
fn process_events(&mut self) {
(self.callback)();
}
}
fn simple_callback() {
println!("hello");
}
fn main() {
let mut p = Processor {
callback: Box::new(simple_callback),
};
p.process_events();
let s = "world!".to_string();
let callback2 = move || println!("hello {}", s);
p.set_callback(callback2);
p.process_events();
}
盒装闭包内引用文献的生命周期
'static
c
类型的生命周期限制
set_callback
接受的参数是一种说服编译器相信包含在
c
中的引用的简单方法。 ,它可能是一个引用其环境的闭包,仅引用全局值,因此在回调的整个使用过程中将保持有效。但是静态边界也非常严厉:虽然它接受拥有对象的闭包很好(我们在上面通过制作闭包
move
确保了这一点),但它拒绝引用本地环境的闭包,即使它们只引用到比处理器生命周期更长并且实际上是安全的值。
'static
更不严格。 .但是如果我们只是删除
'static
生命周期从
set_callback
开始,它不再编译。这是因为
set_callback
创建一个新框并将其分配给
callback
字段定义为
Box<dyn FnMut()>
.由于定义没有为装箱的 trait 对象指定生命周期,
'static
是隐含的,并且赋值将有效地扩大生命周期(从回调的未命名的任意生命周期到
'static
),这是不允许的。修复方法是为处理器提供明确的生命周期,并将该生命周期与框中的引用和
set_callback
收到的回调中的引用联系起来。 :
struct Processor<'a> {
callback: Box<dyn FnMut() + 'a>,
}
impl<'a> Processor<'a> {
fn set_callback(&mut self, c: impl FnMut() + 'a) {
self.callback = Box::new(c);
}
// ...
}
随着这些生命周期的明确,不再需要使用
'static
.闭包现在可以引用本地
s
对象,即不再必须是
move
,前提是
s
的定义放在
p
的定义之前以确保字符串比处理器生命周期更长。
关于callback - Rust 中的惯用回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41081240/
在我的上一个项目中,我使用了 rxJava,我意识到 observable.doOnError('onErrorCallback').subscribe(action) 和 observable.su
我是一名 C++ 初学者,我认为要真正学习指针和引用,我应该尝试创建一个回调函数,这是我在 JavaScript 中认为理所当然的事情。 但是,对于我的一生,我不知道为什么这些括号在 (*callba
我在库中有一个类,它具有在事件发生时执行的“onMessage”方法。 OnMessage 在执行时需要调用属于主应用程序中的类的“回调”方法。我假设这将通过构造函数完成,但我不知道它是如何实现的。
两者的 jQuery 文档基本上说明了相同的事情,所以我想知道两者之间是否有任何重大差异(如果有的话)。谢谢! 最佳答案 这方面的文档实际上非常糟糕,所以这是我在 studying the sourc
这个问题在这里已经有了答案: Using &&'s short-circuiting as an if statement? (6 个答案) Omitting the second expressi
我正在尝试在 golang 中定义一个回调: package main func main() { x, y := "old x ", "old y" callback
我有一个页面,其中包含从 Google 电子表格生成的许多图表。 典型代码如下所示: var url = "http://my.googlespreadsheet.com/tq?argumentshe
当我运行 linter 时,它显示: subscribe is deprecated: Use an observer instead of an error callback 代码来自 this a
对于异步套接字 // accept ... listener.BeginAccept( new AsyncCallback(AcceptCallback), listener); // listene
我希望能够根据在前面的函数中调用的是 callback(true) 还是 callback(false) 在回调函数中执行一些逻辑。 示例: foo.doFunction = function (pa
从 jQuery.scrollTo.js 库中看到这个 block (在 v1.4 的第 184 行)。 function animate( callback ){ $elem.animate
我正在尝试在我的应用中使用一些回调,它与 "callback(value)" 和 "callback.invoke(value)" 一起工作正确调用回调。 我想知道“回调(值)”是否只是一个缩短版本,
我决定从 keras 切换到 tf.keras(建议使用 here)。因此我安装了 tf.__version__=2.0.0和 tf.keras.__version__=2.2.4-tf .在我的旧版
我认为这实际上可能会回答我关于 Stack Overflow 的另一个问题如果我能确认这一点。 返回回调和只调用回调有什么区别? 我看到代码执行其中之一/或/两者,并试图思考为什么以及何时执行哪个。
我目前正在学习 Rust 并希望用它来开发 GUI基于 GTK+ 的应用程序。我的问题与注册回调有关在这些回调中响应 GTK 事件/信号和变异状态。我有一个有效但不优雅的解决方案,所以我想问一下是否有
我在回调函数中传递参数时遇到问题。我使用 redux-form,当我更改 SkinList 中的选择时,它会触发 onChange 回调 - activeSkinChange 方法 在activeSk
我有 8 个相互依赖的回调。我的想法是要有一个更具可读性的过程,但我不明白如何处理这个问题。 我的回调 hell 的一个例子是: return new Promise(function (resolv
因此,我的函数接受一个值和任意数量的回调作为参数(我应该使用扩散操作符吗?)该函数应该返回通过所有给定回调传递该值的最终结果。。我返回的“CB2(Res1)”不是一个函数。如何将第一个回调的结果传递给
在谈到 future 和回调时,documentation说是 The Vert.x core APIs are based on callbacks to notify of asynchronou
我开始觉得自己很蠢。我正在关注 Facebook-Connect 演示“The Run Around”。 当我导航到 http://www.[mysite].com/testing/register_
我是一名优秀的程序员,十分优秀!