标签: trait-objects

当T是特征对象时,如何创建Box <T>?

我有以下代码

extern crate rand;
use rand::Rng;

pub struct Randomizer {
    rand: Box<Rng>,
}

impl Randomizer {
    fn new() -> Self {
        let mut r = Box::new(rand::thread_rng()); // works
        let mut cr = Randomizer { rand: r };
        cr
    }

    fn with_rng(rng: &Rng) -> Self {
        let mut r = Box::new(*rng); // doesn't work
        let mut cr = Randomizer { rand: r };
        cr
    }
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)

它抱怨说

error[E0277]: the trait bound `rand::Rng: std::marker::Sized` is not satisfied
  --> src/main.rs:16:21 …
Run Code Online (Sandbox Code Playgroud)

rust trait-objects

3
推荐指数
1
解决办法
846
查看次数

如何克隆 Rc 特征对象并将其转换为另一个特征对象?

这是来自不同 taits 之间的 Rust dynamic cast trait object的后续问题。当我们对 trait 对象使用引用时,那里提供的解决方案非常有效,但这次我试图用Rc指针做同样的事情。例如

  • 我有一个名为的超级特征TraitAB和 2 个名为TraitA和的特征TraitB
  • 所以当我第一次创建一个 trait 对象TraitAB而不是使用 a 时Box,现在我使用了一个Rc指针。
  • 我需要一个类型的变量TraitA作为参考ab

在这里,我做了一个非常小的例子:

use std::rc::Rc;

trait TraitAB: TraitA + TraitB {
    fn as_a(&self) -> Rc<dyn TraitA>;
    fn as_b(&self) -> Rc<dyn TraitB>;
}

trait TraitA {}
trait TraitB {}

struct MyType {}

impl TraitAB for MyType {
    fn as_a(&self) -> Rc<dyn TraitA> {
        Rc::clone(self)
    }
    fn …
Run Code Online (Sandbox Code Playgroud)

casting smart-pointers rust trait-objects

3
推荐指数
1
解决办法
601
查看次数

有没有办法将随机数生成器存储为特征对象?

有没有办法在 Rust 中保存通用随机数生成器?我想要一种编写通用代码的方法,例如:

use rand::Rng; // 0.7.2

fn main() {
    // Purely random numbers on the interval 0 to 1
    println!("Pure random");
    let mut rng: Box<dyn rand::Rng> = Box::new(rand::thread_rng());
    for i in 0..10 {
        println!("{}", rng.gen::<f64>());
    }
    println!("");

    // On a seed
    *rng = rand::SeedableRng::seed_from_u64(0);
    for i in 0..10 {
        println!("{}", rng.gen::<f64>());
    }
    println!("");
}
Run Code Online (Sandbox Code Playgroud)

该变量rng使用种子或其他方式保存不同类型的随机数生成器。然而,这段代码存在很多错误,例如:

use rand::Rng; // 0.7.2

fn main() {
    // Purely random numbers on the interval 0 to 1
    println!("Pure random");
    let mut rng: …
Run Code Online (Sandbox Code Playgroud)

traits rust trait-objects

3
推荐指数
1
解决办法
1479
查看次数

为什么我不能用 let _ 创建 trait 对象:Arc&lt;dyn Trait&gt; = value.into()?

use std::sync::Arc;

trait Trait {}
struct TraitImpl {}
impl Trait for TraitImpl {}

fn main() {
    let value = TraitImpl {};
    let _: Arc<dyn Trait> = Arc::new(value);    // compiles
    let _: Arc<dyn Trait> = value.into();       // doesn't compile
}
Run Code Online (Sandbox Code Playgroud)

结果

use std::sync::Arc;

trait Trait {}
struct TraitImpl {}
impl Trait for TraitImpl {}

fn main() {
    let value = TraitImpl {};
    let _: Arc<dyn Trait> = Arc::new(value);    // compiles
    let _: Arc<dyn Trait> = value.into();       // doesn't compile
}
Run Code Online (Sandbox Code Playgroud)

( …

generics traits rust trait-objects

3
推荐指数
1
解决办法
749
查看次数

如何在 Rust 中按值传递装箱的 trait 对象?

我正在编写一些代码,并且有一个带有self按值获取方法的特征。我想在一个Box'd trait 对象上调用这个方法(消耗Box和它的值)。这可能吗?如果是这样,如何?

在代码方面,一个最小的例子看起来像以下(不完整的)代码:

trait Consumable {
    fn consume(self) -> u64;
}
fn consume_box(ptr: Box<dyn Consumable>) -> u64 {
    //what can I put here?
}
Run Code Online (Sandbox Code Playgroud)

我的问题是如何在功能填补consume_box与指定的签名,以便值返回的任何值将通过调用得到consumeBox“d值。

我最初写的

ptr.consume()
Run Code Online (Sandbox Code Playgroud)

作为函数的主体,虽然我意识到这不是一个正确的想法,因为它没有理解我想要Box被消耗的事实,而不仅仅是它的内容,但这是我唯一能想到的. 这不会编译,给出一个错误:

无法移动 dyn Consumable 类型的值:无法静态确定 dyn Consumable 的大小

这对我来说有点令人惊讶,我是 Rust 的新手,我曾想过可能self参数的传递类似于 C++ 中的右值引用(这确实是我想要的 - 在 C++ 中,我可能会通过带有签名的方法来实现它virtual std::uint64_t consume() &&,让std::unique_ptr通过虚拟析构函数清理移动的对象),但我猜 Rust 确实是按值传递,将参数移动到位之前 - 所以它拒绝代码是合理的。

问题是,我不确定如何获得我想要的行为,在那里我可以使用Box'd trait 对象。我尝试使用默认实现向 trait 添加一个方法,认为这可能会让我在 …

traits rust trait-objects

3
推荐指数
1
解决办法
988
查看次数

为什么 Vec.sort() 似乎需要静态生命周期?

这是我遇到的问题的一个大大简化的示例,但是给定了trait Thingwhich implementsOrdstruct Objectwhich implements Thing,我有以下结构:

pub struct MyStruct<'a> {
    my_things: HashMap<i32, Vec<Box<dyn Thing + 'a>>>
}

impl<'a> MyStruct<'a> {
    pub fn new() -> MyStruct<'a> {
        MyStruct {
            my_things: HashMap::new()
        }
    }
    
    pub fn add_object(&mut self, key: i32, obj: Object) {
        if !self.my_things.contains_key(&key) {
            self.my_things.insert(key, Vec::new());
        }
        
        let new_thing: Box<dyn Thing> = Box::new(obj);
        let things = self.my_things.get_mut(&key).unwrap();
        
        things.push(new_thing);
        things.sort();
    }
}
Run Code Online (Sandbox Code Playgroud)

它本质上需要一个密钥和Object,并将该对象添加到HashMapVec使用给定密钥s。我知道这不是执行此操作的最佳方法,但我想让它更简单以进行说明。

编译器在调用 时抱怨things.sort()以下错误:

error[E0308]: …
Run Code Online (Sandbox Code Playgroud)

vector traits lifetime rust trait-objects

3
推荐指数
1
解决办法
69
查看次数

为什么使用盒装对象而不是特征对象?

在《Rust for Rustaceans》一书中,作者写道:

\n
\n

但从广义上讲,您\xe2\x80\x99 将希望在库中使用静态调度,在二进制文件中使用动态调度。在图书馆中,您希望允许用户决定哪种调度最适合他们,因为您不知道他们的需求是什么。

\n
\n

我猜想,在二进制情况下,他指的是:

\n
fn flexible_dispatch_method(_: &dyn MyTrait) {}\n\n// static dispatch\n//\nlet obj = MyType {};\nflexible_dispatch_method(&obj);\n\n// dynamic dispatch\n//\nlet trait_obj: &dyn MyTrait = &MyType {};\nflexible_dispatch_method(trait_obj);\n
Run Code Online (Sandbox Code Playgroud)\n

鉴于上述情况,使用装箱对象而不是特征对象有什么优势?是不是因为需要使用生命周期:

\n
fn return_new_trait_object<\'a>() -> &\'a dyn MyTrait {\n    &MyType {}\n}\n
Run Code Online (Sandbox Code Playgroud)\n

或者还有别的什么?根据我的理解,在动态调度情况下,无论如何,对象需要在堆中分配,所以我认为与装箱对象没有太大区别。

\n

traits rust trait-objects

3
推荐指数
1
解决办法
1101
查看次数

Rust:无法将 `Iterator&lt;Item = Box&lt;Dog&gt;&gt;` 收集到 `Vec&lt;Box&lt;dyn Animal&gt;&gt;` 中

我觉得这段代码应该可以工作,因为在大多数情况下Box<Dog>s 应该能够隐式转换为s:Box<dyn Animal>

struct Dog {}
trait Animal {}
impl Animal for Dog {}

fn main() {
    let _: Vec<Box<dyn Animal>> = [Dog {}, Dog {}]
        .into_iter()
        .map(Box::new)
        .collect();
}
Run Code Online (Sandbox Code Playgroud)

但是,我收到以下编译器错误:

error[E0277]: a value of type `Vec<Box<dyn Animal>>` cannot be built from an iterator over elements of type `Box<Dog>`
    --> src/main.rs:9:10
     |
9    |         .collect();
     |          ^^^^^^^ value of type `Vec<Box<dyn Animal>>` cannot be built from `std::iter::Iterator<Item=Box<Dog>>`
     |
     = help: the trait `FromIterator<Box<Dog>>` is not implemented for …
Run Code Online (Sandbox Code Playgroud)

rust trait-objects

3
推荐指数
1
解决办法
247
查看次数

使用 tokio::spawn 和 Box&lt;dyn Error&gt; 时如何修复“无法在线程之间安全发送”?

这个简单的程序会产生编译器错误:

#[tokio::main]
async fn main() {
    tokio::spawn(async {
        foo().await;
    });
}

async fn foo() {
    let f1 = bar();
    let f2 = bar();

    tokio::join!(f1, f2);
}

async fn bar() -> Result<(), Box<dyn std::error::Error>> {
    println!("Hello world");
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)
error[E0277]: `(dyn std::error::Error + 'static)` cannot be sent between threads safely
   --> src/main.rs:5:18
    |
5   |       tokio::spawn(async {
    |  _____------------_^
    | |     |
    | |     required by a bound introduced by this call
6   | |         foo().await;
7   | |     });
    | …
Run Code Online (Sandbox Code Playgroud)

thread-safety rust trait-objects rust-tokio

3
推荐指数
1
解决办法
1783
查看次数

如何制作具有关联类型的特征的类型擦除版本?

假设有一个集合特征,其项目具有关联类型:

trait CollectionItem {
    // ...
}

trait Collection {
    type Item: CollectionItem;
    
    fn get(&self, index: usize) -> Self::Item;
    // ...
}
Run Code Online (Sandbox Code Playgroud)

Collection我可以以某种方式将其类型擦除为对和特征都使用动态调度的类型吗CollectionItem?即将其包装成如下所示:

struct DynCollection(Box<dyn Collection<Item=Box<dyn CollectionItem>>>);
impl DynCollection {
  fn get(&self, index: usize) -> Box<dyn CollectionItem> {
    // ... what to do here?
  }
}
impl <C: Collection> From<C> for DynCollection {
  fn from(c: C) -> Self {
    // ... what to do here?
  }
}
Run Code Online (Sandbox Code Playgroud)

操场

rust associated-types trait-objects

2
推荐指数
1
解决办法
373
查看次数