将闭包传递给特征方法:期望的类型参数,找到的闭包 [英] Passing closure to trait method: expected type parameter, found closure

查看:61
本文介绍了将闭包传递给特征方法:期望的类型参数,找到的闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对如何使它工作有些困惑,我从真实的东西中剔除了它。我写了一个特征:

  pub trait Renderable< F:Fn(& PropertyTags)> {
fn set_property_changed_callback(& mut self,callback:Option< F>);
}

add_child的'child'参数受限制, PropertyTags 只是一个枚举。我已经包含了 child 类型的模拟实现来演示我的用法:

  pub struct Child< F:Fn(& PropertyTags)> {
property_changed_callback:Option< F> ;,
}

impl< F:Fn(&PropertyTags)>可渲染的F对于儿童F {
fn set_property_changed_callback(& mut self,callback:Option< F>)){
self.property_changed_callback =回调;
}
}

然后将这些用作:

  pub fn add_child< REND,C>(& mut self,child:& mut REND)
其中C:Fn( & PropertyTags),
REND:Renderable< C>
{
let tc = Some(| property_tag:& PropertyTags | {
});

child.set_property_changed_callback(tc);
}

我遇到了错误:

  child.set_property_changed_callback(tc); 
| ^^预期的类型参数,找到了闭包
|
=注意:预期类型`std :: option :: Option< C>`
=注意:发现类型'std :: option :: Option< [closure@src/rendering/mod.rs: 74:31:76:18]>`
=帮助:以下一些功能可以满足您的需求:
-.take()
-.unwrap()

我已经建立了一个最小的游乐场示例,它在此处重现了这些问题: https://play.rust-lang.org/?gist=bcc8d67f25ac620fe062032d8737954b&version=stable&

解决方案

问题是 add_child 声称接受任何 Renderable< C> ,其中 C 可以是实现<$ c的 any 类型$ c> Fn(& PropertyTags),但是此函数尝试为其赋予特定的闭包类型,该闭包类型可能与 C 不同



为了为此, add_child 的签名应如下所示:

  pub fn add_child< REND>(& mut self,child:& mut REND)
其中REND:Renderable< AddChildCallback>

其中 AddChildCallback 是具体名称类型(实现 Fn(& PropertyTags))。



这里的困难在于一方面是闭包类型没有可在Rust代码中使用的名称,另一方面,手动实现 Fn 是不稳定的,因此需要每晚进行编译。



我还将注意到,通过将回调类型设为类型参数,不能将 Renderable 分配给其他回调设置第一个回调后的类型,因为第一个回调将确定 Renderable 的具体类型。



如果您想要一个适用于稳定编译器的解决方案(如Rust一样),这可能适合您的用法。



1.14.0),那么您必须对回调进行装箱。 add_child 的签名将如下所示:

  pub fn add_child< ; REND>(& mut self,child:& mut REND)
其中REND:Renderable< Box< Box< Fn(& PropertyTags)>

此处是更新的游乐场链接,示例实现为 Fn 。请注意, call call_mut call_once 的参数为按照特征定义的要求作为元组传递。为了完整起见,下面复制了代码:

  struct RenderableCallback {

}

impl<'a> Fn<(&’a PropertyTags,)> for RenderableCallback {
extern rust-call fn call(&self,args:(&’a PropertyTags,))->自我::输出{

}
}

impl<’a> FnMut<(&’a PropertyTags,)> for RenderableCallback {
extern rust-call fn call_mut(& mut self,args:(&’a PropertyTags,))->自我::输出{

}
}

impl<’a> FnOnce<(&’a PropertyTags,)>对于RenderableCallback {
type Output =();
extern rust-call fn call_once(self,args:(&’a PropertyTags,))-> Self ::输出{
}
}


I'm a bit stumped on how to get this working, I've cut it down from the real thing. I wrote a trait:

pub trait Renderable<F: Fn(&PropertyTags)> {
    fn set_property_changed_callback(&mut self, callback: Option<F>);
}

Which the 'child' parameter of add_child is restricted by and PropertyTags is just an enum. I've included mock implementations of the type of child to demonstrate my usage:

pub struct Child<F: Fn(&PropertyTags)> {
    property_changed_callback: Option<F>,
}

impl<F: Fn(&PropertyTags)> Renderable<F> for Child<F> {
    fn set_property_changed_callback(&mut self, callback: Option<F>) {
        self.property_changed_callback = callback;
    }
}

Then these would be used as:

pub fn add_child<REND, C>(&mut self, child: &mut REND)
    where C: Fn(&PropertyTags),
        REND: Renderable<C>
{
    let tc = Some(|property_tag: &PropertyTags|{
            });

    child.set_property_changed_callback(tc);
}

I'm getting the error:

child.set_property_changed_callback(tc);
   |                                ^^ expected type parameter, found closure
   |
   = note: expected type `std::option::Option<C>`
   = note:    found type `std::option::Option<[closure@src/rendering/mod.rs:74:31: 76:18]>`
   = help: here are some functions which might fulfill your needs:
 - .take()
 - .unwrap()

I've setup a minimal playground example which reproduces the issues here: https://play.rust-lang.org/?gist=bcc8d67f25ac620fe062032d8737954b&version=stable&backtrace=0

解决方案

The problem is that add_child claims to accept any Renderable<C>, where C can be any type that implements Fn(&PropertyTags), but then the function tries to give it a specific closure type that might not be the same as C.

In order for this to work, add_child's signature should look like this:

pub fn add_child<REND>(&mut self, child: &mut REND)
    where REND: Renderable<AddChildCallback>

where AddChildCallback is the name of a concrete type (that implements Fn(&PropertyTags)).

The difficulty here is that on one hand, closure types don't have a name you can use in your Rust code, and on the other hand, implementing Fn manually is unstable, so it requires a nightly compiler.

I'll also note that by making the callback type a type parameter, a Renderable cannot be assigned a callback of a different type after a first callback has been set, as the first callback will determine the concrete type for the Renderable. This might be fine for your usage, I just wanted to make sure you're aware of that.

If you want a solution that works on stable compilers (as of Rust 1.14.0), then you'll have to box the callback. add_child's signature would then look like this:

pub fn add_child<REND>(&mut self, child: &mut REND)
    where REND: Renderable<Box<Fn(&PropertyTags)>>

Here is an updated playground link with an example implementation of Fn. Note that the parameters for call, call_mut and call_once are passed as a tuple, as is required by the trait definition. The code is reproduced below for completeness:

struct RenderableCallback {

}

impl<'a> Fn<(&'a PropertyTags,)> for RenderableCallback {
    extern "rust-call" fn call(&self, args: (&'a PropertyTags,)) -> Self::Output {

    }
}

impl<'a> FnMut<(&'a PropertyTags,)> for RenderableCallback {
    extern "rust-call" fn call_mut(&mut self, args: (&'a PropertyTags,)) -> Self::Output {

    }
}

impl<'a> FnOnce<(&'a PropertyTags,)> for RenderableCallback {
    type Output = ();
    extern "rust-call" fn call_once(self, args: (&'a PropertyTags,)) -> Self::Output {
    }
}

这篇关于将闭包传递给特征方法:期望的类型参数,找到的闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆