Rust 有可能使用trait作为自由函数的语法糖吗?

Rust 有可能使用trait作为自由函数的语法糖吗?,rust,Rust,我想根据外部数据调用函数, 像这样: struct Foo { data: &'static str, handler: Option<fn (i32) -> String>, } fn aaa_converter(_: i32) -> String { unimplemented!(); } fn bbb_converter(_: i32) -> String { unimplemented!(); } fn main() {

我想根据外部数据调用函数, 像这样:

struct Foo {
    data: &'static str,
    handler: Option<fn (i32) -> String>,
}

fn aaa_converter(_: i32) -> String { unimplemented!(); }
fn bbb_converter(_: i32) -> String { unimplemented!(); }

fn main() {
    let _ = Foo{data: "aaa", handler: Some(aaa_converter)};
    let _ = Foo{data: "bbb", handler: Some(bbb_converter)};
    let _ = Foo{data: "ccc", handler: None};
}
trait Handler {
    fn handle(a: i32) -> String;
}

impl Handler for "aaa" {
    // ...
}
我能找到的最佳匹配是:

trait Handler {
    fn handle(/*&self, */a: i32) -> String;
}

struct aaa;

impl Handler for aaa {
    fn handle(/*&self, */a: i32) -> String {
        unimplemented!();
    }
}

struct Foo {
    data: &'static str,
    handler: &'static Handler,
}

fn main() {}
但这样的代码不会编译:

无法将trait`Handler`制作成对象
=注意:方法“handle”没有接收器
看起来相关,但答案中链接的RFC已过时。也有可能从那以后语言发生了变化

是否可以使用trait作为指向自由函数的简单指针


还是有其他方法来组织处理程序?

这里有一个误解:

  • 锈病具有多种功能
  • Rust有“函子”
  • 锈病有其特点
  • 功能就是:

    fn i_am_a_function(a: i32) -> String { a.to_string() }
    
    函子是一个函数对象,它是与某个状态关联的函数。Rust实际上有三种类型:

    FnOnce(i32) -> String
    FnMut(i32) -> String
    Fn(i32) -> String
    
    最后,锈病具有以下特征:

    trait Handler {
        fn non_object_safe(a: i32) -> String;
        fn object_safe(&self, a: i32) -> String;
    }
    
    特质可用于两种情况:

    • 在泛型函数中提供边界
    • 当对象安全时,提供类型擦除
    粗略地说,如果特征的任何相关功能:

    • 没有
      &self
      &mut self
      参数
    • 提到
      Self
      (类型)
    有关这两个概念的更多信息,请查看铁锈手册


    在您的情况下,您可以使用:

  • 函数的简单指针:
    fn(i32)->String
  • 函子
    Fn(i32)->String
  • 物体安全特性
  • 你唯一不能使用的是非对象安全特性,当然多亏了墨菲,这是你选择的一个选项

    在您的情况下,最简单的解决方案是使用对象安全特性:

    trait Handler {
        fn handle(&self, a: i32) -> String;
    }
    
    struct A;
    
    impl Handler for A {
        fn handle(&self, a: i32) -> String {
            a.to_string()
        }
    }
    
    const STATIC_A: &'static Handler = &A;
    
    struct Foo {
        data: &'static str,
        handler: &'static Handler,
    }
    
    fn main() {
        let foo = Foo { data: "aaa", handler: STATIC_A };
        println!("{}", foo.handler.handle(3));
    }
    
    如果数据指针的64位开销真的让您烦恼,那么您可以使用函数指针并构建自己的虚拟表:

    struct Handler {
        handle: fn(i32) -> String,
    }
    
    fn aaa(a: i32) -> String {
        a.to_string()
    }
    
    const STATIC_A: &'static Handler = &Handler { handle: aaa };
    
    struct Foo {
        data: &'static str,
        handler: &'static Handler,
    }
    
    fn main() {
        let foo = Foo { data: "aaa", handler: STATIC_A };
        println!("{}", (foo.handler.handle)(3));
    }
    

    它不太符合人体工程学,但它也小了64位

    为什么??为什么不只使用一个空结构,使用
    self
    参数,而不使用它?@Shepmaster:为什么要使用trait作为开头?;)@马蒂厄姆。我的蜘蛛侠意识告诉我,有时候他们会想要国家。例如,
    Foo
    可能是实际的处理程序,
    data
    应该通过
    self
    @Shepmaster进行访问:公平地说,编译器很难删除数据指针,因为
    处理程序的一个实现实际上可以完美地使用数据指针。@user1244932:您的问题还很不清楚。从您的评论来看,您似乎希望
    处理程序
    具有多个关联函数;如果是这样的话,它应该反映在问题中!(当你提到许多转换器时,我假设
    Foo
    的一个实例将有一个转换器/函数,因为
    Handler
    有一个函数,而你将有多个
    Foo
    的实例)没有,正如我在问题中指出的,我已经使用了你展示的代码。问题是我有很多这样的函数,比如
    aaa
    ,为了组织它们,我需要一些类似traits的东西来简化在代码中找到合适的函数,并向其他人展示应该更新的接口;我建议在本例中使用trait对象,除非您确实有严格的要求,但以防我演示了如何自己构建虚拟表。