Trouble creating object safe trait


#1

I would like to create a vector of trait objects that I can iterate over. However, I am having trouble because my trait is not object-safe. Is it the fact that my write() method takes a reference to a Write trait? Is there a way around this?

use std::io::{Write};
use std::boxed::Box;

trait FormatOutput {
    fn write<T: Write>(&self, w: &mut T);
}

struct FormatOutputImpl;
impl FormatOutput for FormatOutputImpl {
    fn write<T: Write>(&self, w: &mut T){
        w.write(format!("hello world!\n").as_bytes()).unwrap();
    }
}

fn main() {
    let mut fov: Vec<Box<FormatOutput>> = Vec::new();
    fov.push(Box::new(FormatOutputImpl));
}

This generates the following output:

cargo build
Compiling hello-world v0.1.0 (file:///work/tmp)
src/main.rs:17:14: 17:40 error: cannot convert to a trait object because trait FormatOutput is not object-safe [E0038]
src/main.rs:17 fov.push(Box::new(FormatOutputImpl));


#2

Yes and no. Yes, it is your write method, but it does not take a reference to a Write trait; it takes a reference to an arbitrary type that implements Write, which are two very different things.

All methods in an object-safe trait need to be non-generic over types. Try changing the method signature to fn write(&self, w: &Write), which actually takes a reference to a Write.


#3

That you! That worked and I was able to do the following:

use std::io::{Write, BufWriter};
use std::boxed::Box;

trait FormatOutput {
    fn write(&self, w: &mut Write);
}

struct FormatOutputImpl;
impl FormatOutput for FormatOutputImpl {
    fn write(&self, w: &mut Write){
        w.write(format!("hello world!\n").as_bytes()).unwrap();
    }
}

fn main() {
    let mut w = BufWriter::new(std::io::stdout());

    let mut fov: Vec<Box<FormatOutput>> = Vec::new();
    fov.push(Box::new(FormatOutputImpl));
    for v in fov {
        v.write(&mut w);
    }
}