3
votes

I got this code which creates a struct with a single field that is of a Command type. The struct implements the Clone trait.

use std::process::Command;

struct Instruct {
    command: Command
}

impl Clone for Instruct { 
    fn clone(&self) -> Self {
        Self {
            command: self.command.clone() // this causes an error
        }
    }
}

impl Instruct {
    fn new(cmd: &str) -> Instruct {
        let command = Command::new(cmd);

        Instruct {
            command
        }
    }
}

fn main() {
    let mut child1 = Instruct::new("sh");
    let mut child2 = child1.clone(); // this errors of course

    child1.command.arg("echo hello A");
    child2.command.arg("echo hello B");
}

But this does not work because the Copy and Clone trait does not exist on Command, so it cannot be copied and you cannot call the clone method.

std::process::Command, which does not implement the Copy trait

OR

no method named `clone` found for struct `std::process::Command` in the current scope

What I am after is declaring the struct Instruct once and I would like to be able to clone it and use the command field more than once.

Is it possible to implement the Copy and Clone trait to Command or to the struct that is holding it?

1
Due to os-specific implementations, Rust doesn't offer cloning for commands, and it'd be very dubious and probably unsafe to try to clone one. If you really want "command" cloning, you should make a command-like struct that has fields for everything you want to modify, then actually turn it into a Command when you want to use it.Aplet123
@Stargateur that doesn't explain how Clone/Copy would be implemented on this wrapper type though? There is already a wrapper type being used in the question.Smitop

1 Answers

1
votes

No, implementing Copy and Clone is impossible, since Command does not implement Copy or Clone itself. It wouldn't make sense for Command to implement any of those types either, since it holds owned data and closures. Here's what Command is a wrapper around on Unix platforms:

pub struct Command {
    program: CString,
    args: Vec<CString>,
    argv: Argv,
    env: CommandEnv,
    cwd: Option<CString>,
    uid: Option<uid_t>,
    gid: Option<gid_t>,
    saw_nul: bool,
    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
    groups: Option<Box<[gid_t]>>,
    stdin: Option<Stdio>,
    stdout: Option<Stdio>,
    stderr: Option<Stdio>,
}