我是Rust的一名新手,我试图对这种语言的基础有所了解。
考虑以下特征
trait Function {
fn value(&self, arg: &[f64]) -> f64;
}
和两个实现它的结构:
struct Add {}
struct Multiply {}
impl Function for Add {
fn value(&self, arg: &[f64]) -> f64 {
arg[0] + arg[1]
}
}
impl Function for Multiply {
fn value(&self, arg: &[f64]) -> f64 {
arg[0] * arg[1]
}
}
在我的main()
函数中,我想将Add
和Multiply
的两个实例组合在一个向量中,然后调用value
方法。以下作品:
fn main() {
let x = vec![1.0, 2.0];
let funcs: Vec<&dyn Function> = vec![&Add {}, &Multiply {}];
for f in funcs {
println!("{}", f.value(&x));
}
}
也是如此:
fn main() {
let x = vec![1.0, 2.0];
let funcs: Vec<Box<dyn Function>> = vec![Box::new(Add {}), Box::new(Multiply {})];
for f in funcs {
println!("{}", f.value(&x));
}
}
有没有更好/更详细的方法?我可以解决将实例包装在Box
中的问题吗?在这种情况下,带有特征对象的外卖是什么?
答案 0 :(得分:1)
有没有更好/更详细的方法?
实际上没有一种方法可以使它变得不那么冗长。由于您正在使用特征对象,因此需要告诉编译器,向量的项是dyn Function
而不是具体类型。编译器不能仅仅推断出您的意思是dyn Function
个特征对象,因为Add
和Multiply
可能还具有其他特征。
您也不能抽象出对Box::new
的调用。为此,您必须以某种方式映射到异构集合,这在Rust中是不可能的。但是,如果您正在编写大量内容,则可以考虑为每个具体的impl
添加辅助构造函数:
impl Add {
fn new() -> Add {
Add {}
}
fn new_boxed() -> Box<Add> {
Box::new(Add::new())
}
}
在任何可能的地方都包含new
构造函数是很习惯的做法,但通常也包括其他便利构造函数。
这使向量的构造噪音更少:
let funcs: Vec<Box<dyn Function>> = vec!(Add::new_boxed(), Multiply::new_boxed()));
在这种情况下,带有特征对象的外卖是什么?
使用动态分派始终会降低性能。如果所有对象都是同一类型,则可以将它们密集地包装在内存中,这样可以更快地进行迭代。通常,除非您要创建库箱,或者您真的想挤出性能的最后一纳秒,否则我不会对此太担心。