微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在 Rust 中使用方法作为函数指针

如何解决如何在 Rust 中使用方法作为函数指针

我有一个 trait 方法需要改变结构的内部数据,我希望我可以将 setter 方法作为参数传递给 trait 方法。我想这样做,以便我可以通过指定作为参数传递的函数来灵活处理发生变异的内容

这段代码是我想要做的事情的简化,它有同样的编译器问题。

谢谢

代码

struct MyStruct {
    i: usize
}

impl MyStruct {
    fn set_i(mut self,i: usize) -> Self {
        self.i = i;
        self
    }
    fn new() -> Self{
        MyStruct{ i: 0 }
    }
}

trait MyTrait {
    fn do_some_setting(&mut self,setter_function: fn(&mut Self,usize) -> Self ) {
        setter_function(&mut self,7);
    }
}

impl MyTrait for MyStruct {}


fn main() {
    let mut s = MyStruct::new()
                .set_i(3);
                
    assert_eq!(s.i,3);
    
    s.do_some_setting(MyStruct::set_i);
    
    assert_eq!(s.i,7);
}

问题

error[E0308]: mismatched types
  --> src/main.rs:27:23
   |
27 |     s.do_some_setting(MyStruct::set_i);
   |                       ^^^^^^^^^^^^^^^ expected `&mut MyStruct`,found struct `MyStruct`
   |
   = note: expected fn pointer `for<'r> fn(&'r mut MyStruct,_) -> MyStruct`
                 found fn item `fn(MyStruct,_) -> MyStruct {MyStruct::set_i}`

解决方法

这不起作用,因为 MyTrait::do_some_setting 需要一个函数,其第一个参数的类型为 &mut Self,而 MyStruct::set_i 的第一个参数的类型为 mut self

您可以通过将 MyStruct::set_i 的签名更改为 set_i(&mut self,i: usize) 来解决此问题,但是编译器会抱怨 mismatched types,因为它期望 MyStruct::set_i 返回 Self但您会返回 &mut Self。您可以派生 Clone 并在克隆后返回该结构,也可以将签名中的返回类型更改为 &mut Self

编译器将再次抱怨类型不匹配,因为 setter_function 中的 MyTrait::do_some_setting 是返回 Self 而不是 &mut Self 的函数。您必须更改 setter_function 的签名以返回 &mut Self

编译器现在会在 temporary value dropped while borrowed 处抱怨 let mut s = MyStruct::new().set_i(3)。您必须先创建 MyStruct,然后在其上使用 set_i

最后,您将得到如下所示的代码:

struct MyStruct {
    i: usize,}

impl MyStruct {
    fn set_i(&mut self,i: usize) -> &mut Self {
        self.i = i;
        self
    }
    fn new() -> Self {
        MyStruct { i: 0 }
    }
}

trait MyTrait {
    fn do_some_setting(&mut self,setter_function: fn(&mut Self,usize) -> &mut Self) {
        setter_function(self,7);
    }
}

impl MyTrait for MyStruct {}

fn main() {
    let mut s = MyStruct::new();
    s.set_i(3);

    assert_eq!(s.i,3);

    s.do_some_setting(MyStruct::set_i);

    assert_eq!(s.i,7);
}

Playground Link

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。