liveBook · Manning

Command

As explained in Idiomatic Rust

The command pattern encapsulates an action as an object or value so its execution can be separated from the receiver and controlled in order or timing.

The command pattern packages instructions in structures that implement a shared `Command` trait. Each command acts on a receiver, separating what executes from the target and from when or in what order it executes. section 5.6 section 5.8

A command’s `execute` method can return `Result<(), Error>` to propagate failures. Concrete command types hold the receiver and any needed data; clients can store them behind `Box<dyn Command>` and execute them in sequence. section 5.6.1 section 5.6.2

File commands

A file handle can serve as the receiver for `ReadFile` and `WriteFile` commands. A client places both in a vector of boxed command trait objects and executes them in order. The write example appends content; because it is not idempotent, repeated runs can change the file again. section 5.6.2

Commands can also support forward and reverse operations, as in undo/redo, but that requires tracking state and making operations idempotent. The simple file example does not provide that; consider whether this widely used but loosely specified pattern is worthwhile for the task. section 5.6 section 5.6.2

Listing 5.15 Command trait definition
trait Command {
    fn execute(&self) -> Result<(), Error>;
}

See the minimal `Command` trait and its result type. section 5.6.1

Listing 5.18 Client implementation for command pattern
use std::fs::File;
use std::io::{BufRead, BufReader, Error, Seek, Write};

fn main() -> Result<(), Error> {
    let file = File::options()     #1
        .read(true)
        .write(true)
        .create(true)
        .append(true)
        .open("file.txt")?;

    let commands: Vec<Box<dyn Command>> = vec![     #2
        ReadFile::new(file.try_clone()?),          #3
        WriteFile::new(
          "file content\n".into(), file.try_clone()?    #4
        ),
        ReadFile::new(file.try_clone()?),
    ];

    for command in commands {   #5
        command.execute()?;
    }

    Ok(())
}

See how a client stores and executes concrete commands through boxed trait objects. section 5.6.2

How Idiomatic Rust covers it

How deep it goes
Defines a result-returning trait and demonstrates file commands, stopping short of implementing a complete undo/redo framework.
Examples
Demonstrates file-reading and file-writing commands stored in an ordered vector.
What it assumes
Assumes familiarity with Rust traits and trait objects rather than teaching those mechanics from zero.
What you can do after
Build a simple Rust command abstraction with a shared trait, concrete file operations, and ordered client execution.
How it connects
Connects traits, trait objects, file I/O, idempotency, and undo/redo operations.

Also explained in

Compare how 5 books explain command →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Idiomatic Rust. The section links point to the parts of the book it draws on.