我想根据外部数据调用函数, 像这样:
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};
}
我输入字符串&#34; aaa&#34;,我需要拨打aaa_converter
。一切正常,我将Foo
个对象放入哈希映射中,如果不是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() {}
但是这样的代码无法编译:
the trait `Handler` cannot be made into an object
= note: method `handle` has no receiver
How to call a trait method without a struct instance?看起来很相关,但答案中链接的RFC已过时。从那时起,语言中也可能发生了一些变化吗?
是否可以将特征用作指向自由函数的简单指针?
或者是否有另一种组织处理程序的方法?
答案 0 :(得分:1)
这里有一个误解:
一个功能只是:
fn i_am_a_function(a: i32) -> String { a.to_string() }
仿函数是一个函数对象,它是与某个状态相关联的函数。 Rust实际上有3个:
FnOnce(i32) -> String
FnMut(i32) -> String
Fn(i32) -> String
最后Rust有这样的特点:
trait Handler {
fn non_object_safe(a: i32) -> String;
fn object_safe(&self, a: i32) -> String;
}
特征可以在两种情况下使用:
粗略地说,如果某个特征与其相关的任何功能都不是对象安全的:
&self
或&mut self
参数Self
(类型)有关这两个概念的更多信息,请查看Rust Book。
在您的情况下,您可以使用:
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位!