标签: trait-objects

特征不能成为一个对象

我有以下代码:

extern crate futures; // 0.1.24

use futures::Future;
use std::io;

struct Context;

pub trait MyTrait {
    fn receive(context: Context) -> Future<Item = (), Error = io::Error>;
}

pub struct MyStruct {
    my_trait: MyTrait,
}
Run Code Online (Sandbox Code Playgroud)

当我尝试编译它时,我收到错误消息:

error[E0038]: the trait `MyTrait` cannot be made into an object
  --> src/lib.rs:13:5
   |
13 |     my_trait: MyTrait,
   |     ^^^^^^^^^^^^^^^^^ the trait `MyTrait` cannot be made into an object
   |
   = note: method `receive` has no receiver
Run Code Online (Sandbox Code Playgroud)

我想我知道它为什么会发生,但我如何从结构中引用特征呢?可能吗?也许还有其他方法可以实现相同的行为?

generics traits dynamic-dispatch rust trait-objects

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

如何返回带有一般错误的结果

我想编写一个函数来读取文件的内容,并在失败时引发错误。我想从 python 脚本调用这个函数,所以我在下面提到了一些 Python 以防它可能相关。

正如我在评论中尝试显示的那样,可能会发生更多的工作,从而引发其他类型的错误,因此,如果可能的话,我想使用通用错误(如果 Rust 中可以实现)(?)。如何返回错误,以便可以对其进行处理并将其包装在 python 错误中,如图所示do_work?不确定我导致以下错误的方法是否方向正确。

fn work_with_text() -> Result<(), dyn std::error::Error> {
    let content = match std::fs::read_to_string("text.txt") {
        Ok(t) => t,
        Err(e) => return Err(e),
    };
    // do something with content that may cause another type of error (rusqlite error)
    Ok(())
}
    

#[pyfunction]
fn do_work(_py: Python) -> PyResult<u32> {
    match work_with_text() {
        Ok(_) => (0),
        Err(e) => {
            let gil = Python::acquire_gil();
            let py = gil.python();
            let error_message = format!("Error happened {}", e.to_string()); …
Run Code Online (Sandbox Code Playgroud)

polymorphism error-handling traits rust trait-objects

15
推荐指数
1
解决办法
1万
查看次数

在Rust中的线程之间发送特征对象

我想在任务之间发送一个特征对象,但无法弄清楚它是否可能.它似乎可能不是,因为它们显然不符合这一Send特性.

以下代码演示了我正在尝试做的事情:

use std::{
    sync::mpsc::{channel, Receiver, Sender},
    thread,
};

trait Bar {
    fn bar(&self);
}

struct Foo {
    foo: i32,
}

impl Bar for Foo {
    fn bar(&self) {
        println!("foo: {}", self.foo);
    }
}

fn main() {
    let foo = Box::new(Foo { foo: 1 }) as Box<dyn Bar>;

    let (tx, rx): (Sender<Box<dyn Bar>>, Receiver<Box<dyn Bar>>) = channel();

    thread::spawn(move || {
        tx.send(foo).unwrap();
    });

    let sent = rx.recv().unwrap();

    sent.bar();
}
Run Code Online (Sandbox Code Playgroud)

此操作失败,并显示以下消息:

error[E0277]: `dyn Bar` cannot be sent between threads safely …
Run Code Online (Sandbox Code Playgroud)

rust trait-objects

14
推荐指数
1
解决办法
2907
查看次数

为什么具有泛型类型参数的特征方法是对象不安全的?

引用这本书(强调我的),

当使用特征时,用具体类型参数填充的泛型类型参数也是如此:具体类型成为实现该特征的类型的一部分。当通过使用特征对象而忘记类型时,就无法知道用什么类型填充泛型类型参数。

我无法理解其中的道理。对于具体示例,请考虑以下内容

pub trait Echoer {
    fn echo<T>(&self, v: T) -> T;
}

pub struct Foo { }

impl Echoer for Foo {
    fn echo<T>(&self, v: T) -> T {
        println!("v = {}", v);
        return v;
    }
}

pub fn passthrough<T>(e: Box<dyn Echoer>, v: T) {
    return e.echo(v);
}

fn main() {
    let foo = Foo { };
    passthrough(foo, 42);
}
Run Code Online (Sandbox Code Playgroud)

结果当然是报错

$ cargo run
   Compiling gui v0.1.0 (/tmp/gui)
error[E0038]: the trait `Echoer` cannot be made into …
Run Code Online (Sandbox Code Playgroud)

generics polymorphism traits rust trait-objects

12
推荐指数
1
解决办法
5517
查看次数

是否为所有实现特征的类型生成虚函数表?

如果我有一个特质Foo,并且有一些实现者BarBaz.

impl Foo for Bar {
}
Run Code Online (Sandbox Code Playgroud)
impl Foo for Baz {
}
Run Code Online (Sandbox Code Playgroud)

但是假设我只使用其中一个作为特征对象,

let bar = Bar {..};
let foo: &dyn Foo = &bar;

Run Code Online (Sandbox Code Playgroud)

那么我的二进制文件仍然有两个 vtable 吗?这种行为在调试和发布版本之间是否会发生变化?

traits vtable rust trait-objects

11
推荐指数
1
解决办法
1593
查看次数

函数返回一个闭包不在我的过滤器内工作

我不能在不使用闭包的情况下编译它.我试图让函数apply首先返回正确的闭包.

#![feature(conservative_impl_trait)]
#![allow(dead_code)]

fn accumulate<'a>(tuples: &[(&'a str, &Fn(i32) -> bool)], i: i32) {

    // this works
    let _ = tuples.iter().filter(|t| apply(second, i)(t));

    // this doesn't
    //let f = apply(second, i);
    //let _ = tuples.iter().filter(f);

    //this works as well

    let f  = |t: &&(_,_)| apply(second, i)(t);
    let _ = tuples.iter().filter(f);
}

fn apply<A, B, C, F, G>(mut f: F, a: A) -> impl FnMut(B) -> C
         where F: FnMut(B) -> G,
               G: FnMut(A) -> C,
               A: Clone
{
    move …
Run Code Online (Sandbox Code Playgroud)

closures rust trait-objects

10
推荐指数
1
解决办法
2303
查看次数

<T:Trait> Box <T>和&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);
}
Run Code Online (Sandbox Code Playgroud)

或直接使用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);
}
Run Code Online (Sandbox Code Playgroud)

这些输出相同.那么区别是什么呢?

(这个问题的灵感来自另一个问题,这只是几个混合概念中的一个)

traits rust trait-objects

10
推荐指数
2
解决办法
542
查看次数

如何将 Rc&lt;RefCell&lt;Box&lt;MyStruct&gt;&gt;&gt; 传递给接受 Rc&lt;RefCell&lt;Box&lt;dyn MyTrait&gt;&gt;&gt; 的函数?

我最初在这里问过这个问题,但它被标记为重复,尽管在我看来它只重复了其中的一部分,所以我创建了一个更具体的问题:

考虑以下代码:

use std::rc::Rc;

trait MyTrait {
    fn trait_func(&self);
}

struct MyStruct1;

impl MyStruct1 {
    fn my_fn(&self) {
        // do something
    }
}

impl MyTrait for MyStruct1 {
    fn trait_func(&self) {
        // do something
    }
}

fn my_trait_fn(t: Rc<dyn MyTrait>) {
    t.trait_func();
}

fn main() {
    let my_str: Rc<MyStruct1> = Rc::new(MyStruct1);
    my_trait_fn(my_str.clone());
    my_str.my_fn();
}
Run Code Online (Sandbox Code Playgroud)

这段代码工作正常。现在我想更改 的定义trait_func以接受 a &mut self,但它不会像Rc仅适用于不可变数据那样工作。我使用的解决方案是包装MyTraitRefCell

use std::cell::RefCell;

fn my_trait_fn(t: Rc<RefCell<Box<dyn MyTrait>>>) {
    t.borrow_mut().trait_func();
}

fn …
Run Code Online (Sandbox Code Playgroud)

smart-pointers rust trait-objects

8
推荐指数
1
解决办法
2332
查看次数

无法克隆Vec <Box <Trait >>因为Trait无法成为对象

我正在尝试克隆盒装特征的向量.自然地简单地派生Clone所有实现我的特征的结构是不够的,因为编译器在编译时不知道实现特征的所有结构都有Clone.

好的,所以我接着尝试使用Clonesupertrait,但这只会导致标题中的错误.我对解决方案感到茫然.

这是最小工作实现(或不工作,因为我无法克隆)

#![allow(dead_code, unused_macros)]
use std::fmt::Debug;

trait MusicElement: Debug + Clone {
    fn duration(&self) -> f32;
}

#[derive(Debug, Clone)]
struct Note<'a> {
    name: &'a str,
    duration: f32,
}

impl<'a> MusicElement for Note<'a> {
    fn duration(&self) -> f32 {
        self.duration
    }
}

#[derive(Debug, Clone)]
struct Pause {
    duration: f32,
}

impl MusicElement for Pause {
    fn duration(&self) -> f32 {
        self.duration
    }
}

#[derive(Debug, Clone)]
struct Sequence {
    elements: Vec<Box<MusicElement>>,
}

impl MusicElement for …
Run Code Online (Sandbox Code Playgroud)

clone rust trait-objects

8
推荐指数
1
解决办法
1477
查看次数

特征对象的&mut和ref mut之间的区别

首先,我不是问&mutref mut本身有什么区别.

我在问,因为我想:

let ref mut a = MyStruct
Run Code Online (Sandbox Code Playgroud)

是相同的

let a = &mut MyStruct
Run Code Online (Sandbox Code Playgroud)

考虑从函数返回特征对象.你可以退还一个Box<Trait>或一个&Trait.如果您希望对其方法进行可变访问,是否可以返回&mut Trait

鉴于这个例子:

trait Hello {
    fn hello(&mut self);
}

struct English;
struct Spanish;

impl Hello for English {
    fn hello(&mut self) {
        println!("Hello!");
    }
}

impl Hello for Spanish {
    fn hello(&mut self) {
        println!("Hola!");
    }
}
Run Code Online (Sandbox Code Playgroud)

该方法接收可变参考用于演示目的.

这不会编译:

fn make_hello<'a>() -> &'a mut Hello {
    &mut English
}
Run Code Online (Sandbox Code Playgroud)

也不是这样

fn make_hello<'a>() -> &'a …
Run Code Online (Sandbox Code Playgroud)

mutable traits rust trait-objects

7
推荐指数
1
解决办法
520
查看次数