Rust <;T:特质>;盒子<;T>;及;特质/盒<;特质>;?

Rust <;T:特质>;盒子<;T>;及;特质/盒<;特质>;?,rust,traits,trait-objects,Rust,Traits,Trait Objects,编写带有特征的代码时,可以将特征放入特征绑定中: 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)); myfunct

编写带有特征的代码时,可以将特征放入特征绑定中:

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);
}
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绑定来告诉编译器您想要一个
Box
,它带有一个实现
trait
的类型
T
的实例,并且在使用它时您将指定
T
。Rust编译器可能会为代码中的每个不同
T
创建不同、高效的代码(单聚合)

使用
Box
告诉编译器,您想要一个带有trait对象的
Box
,一个指向实现
trait
的未知类型的指针,这意味着编译器将使用动态分派

我列举了两个例子,使区别更加明显:

,即特征绑定:

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);
}
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"));
}
使用std::fmt::Debug;
结构包装器{
内容:选项,
}
impl包装器{
fn new()->Wrapper{
包装{内容:无}
}
fn插入(&mut self,val:Box){
}
}
fn main(){
让mut w=Wrapper::new();
//使w的T为整数类型,例如Box
w、 插入(框:新的(5));
//类型错误,&str不是整数类型
//w.插入(方框::新(“你好”);
}
,即特征对象:

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"));
}
使用std::fmt::Debug;
结构包装器{
内容:选项,
}
impl包装器{
fn new()->Wrapper{
包装{内容:无}
}
fn插入(&mut self,val:Box){
}
}
fn main(){
让mut w=Wrapper::new();
w、 插入(框:新的(5));
w、 插入(方框::新(“您好”);
}

有关特征边界和特征对象之间差异的更多详细信息,我建议。

重要的是,您不必将泛型类型置于引用后面(如
&
),您可以直接接受它:

fn myfunction3<T: Debug>(v: T) {
    println!("{:?}", v);
}

fn main() {
    myfunction3(5);
}
fn myfunction3(v:T){
println!(“{:?}”,v);
}
fn main(){
我的职能3(5);
}
这与单晶化的好处相同,没有额外内存分配(
Box
)的缺点,也不需要将值的所有权保留在某个地方(
&

我想说,泛型通常应该是默认选择——只有在存在动态分派/异构性时,才需要trait对象