在编写带有特征的代码时,您可以将该特性放在一个特征绑定中:
use std::fmt::Debug;
fn myfunction1<T: Debug>(v: Box<T>) {
println!("{:?}", v);
}
fn myfunction2<T: Debug>(v: &T) {
println!("{:?}", v);
}
fn main() {
myfunction1(Box::new(5));
myfunction2(&5);
}或直接在Box或引用类型中:
use std::fmt::Debug;
fn myfunction3(v: Box<Debug>) {
println!("{:?}", v);
}
fn myfunction4(v: &Debug) {
println!("{:?}", v);
}
fn main() {
myfunction3(Box::new(5));
myfunction4(&5);
}它们给出了同样的输出。那有什么区别呢?
(这个问题是由另一个问题提出的,这只是几个混合概念中的一个)
发布于 2017-07-17 19:02:39
使用<T: Trait> Box<T>时,您使用一个绑定的特性告诉编译器,您想要一个具有实现Trait的某种类型的T实例的Box,在使用它时,您将指定T。Rust编译器可能会为代码中的每个不同的T创建不同的、高效的代码(单体化)。
使用Box<Trait>时,您正在告诉编译器,您需要一个带有属性对象的Box,一个指向实现Trait的未知类型的指针,这意味着编译器将使用动态调度。
我列举了两个例子,让区别变得更清楚了:
<T: Trait> Box<T>,即性状绑定:
use std::fmt::Debug;
struct Wrapper<T> {
contents: Option<Box<T>>,
}
impl<T: Debug> Wrapper<T> {
fn new() -> Wrapper<T> {
Wrapper { contents: None }
}
fn insert(&mut self, val: Box<T>) {
}
}
fn main() {
let mut w = Wrapper::new();
// makes T for w be an integer type, e.g. Box<i64>
w.insert(Box::new(5));
// type error, &str is not an integer type
// w.insert(Box::new("hello"));
}Box<Trait>,即特征对象:
use std::fmt::Debug;
struct Wrapper {
contents: Option<Box<Debug>>,
}
impl Wrapper {
fn new() -> Wrapper {
Wrapper { contents: None }
}
fn insert(&mut self, val: Box<Debug>) {
}
}
fn main() {
let mut w = Wrapper::new();
w.insert(Box::new(5));
w.insert(Box::new("hello"));
}关于特征边界和特征对象之间的差异的更多细节,我建议使用“锈书”第一版中关于特征对象的章节。
发布于 2017-10-30 12:36:27
重要的是,没有将泛型类型放在引用后面(比如&或Box),您可以直接接受它:
fn myfunction3<T: Debug>(v: T) {
println!("{:?}", v);
}
fn main() {
myfunction3(5);
}这具有相同的单一组织化的好处,而不存在额外内存分配(Box)或需要在某个地方保留值的所有权(&)的缺点。
我想说的是,泛型通常应该是默认的选择--只有在动态调度/异质性存在时,才需要特性对象。
https://stackoverflow.com/questions/45151770
复制相似问题