Skip to content

← Ownership I: Moves, Copy, Clone, Drop step 10 of 20

Medium Primitives

Partial moves: taking one field and leaving the rest

Build a record, replace an empty label, then take its fields apart to format one output string per input.

pub fn repack(records: Vec<(i64, String, Vec<String>)>) -> Vec<String>

The grader supplies this type. Do not redefine it or add Clone or Drop:

struct Record {
    id: i64,
    label: String,
    tags: Vec<String>,
}

Required behavior

Each input tuple contains (id, label, tags). Return strings in input order using the format "<id>:<label>[<joined-tags>]".

Replace only an empty label with "anon". Preserve every other label, including whitespace and Unicode. Join tags with +, preserving their order and contents. An empty tag list produces empty brackets; empty tags remain part of the join. Do not escape punctuation in labels or tags.

(1, "a", ["x", "y"]) -> "1:a[x+y]"
(7, "", ["a"])       -> "7:anon[a]"
(0, "z", [])         -> "0:z[]"
(2, " ", ["", "x"]) -> "2: [+x]"

An empty input returns an empty vector. IDs may be any i64 value; format them without performing arithmetic.

Practice field moves

For each tuple:

  1. Construct Record { id, label, tags }.
  2. If its label is empty, rebuild it with Record { label: String::from("anon"), ..r }.
  3. Move label out, then move tags out, then read id.
  4. Format the result from those local values.

Use this sequence and struct update syntax for the exercise. Avoid cloning the fields. Output checks alone do not prove that a solution follows these implementation requirements.

Moving a non-Copy field leaves the record partially moved. Other fields remain available, but the whole record cannot be used until the missing field has been restored. Reading r.id copies its i64; moving r.tags transfers its vector. A remaining field does not have to implement Copy to be moved out separately.

What the starter gets wrong

The starter moves r.label into a local named label before its conditional. Its else branch then tries to move the whole r, causing E0382.

The struct update in the other branch is not the problem. It explicitly supplies a new label, so ..r only needs the remaining id and tags fields. Struct update does not require every source field to be present.

There is also an output mistake: the starter formats the old local label, so rebuilding the record alone would not make the output use "anon". Apply the replacement first, then extract the fields from the resulting record.

Understand struct update

Record { label: new_label, ..r } takes only unspecified fields from r. It copies id because i64 is Copy, and moves tags because Vec<String> is not. It does not read or move r.label.

This complete example shows that replacing an already-moved field is valid:

struct Item {
    name: String,
    tags: Vec<String>,
}

fn main() {
    let item = Item {
        name: String::from("old"),
        tags: vec![String::from("kept")],
    };
    let old_name = item.name;
    let rebuilt = Item {
        name: String::from("new"),
        ..item
    };

    assert_eq!(old_name, "old");
    assert_eq!(rebuilt.name, "new");
    assert_eq!(rebuilt.tags, ["kept"]);
}

By contrast, trying to move item as a whole after extracting item.name would fail. The difference is which fields the operation needs.

Keep field shorthand and destructor rules separate

When a field and local variable have the same name, id is shorthand for id: id in a struct initializer. Clippy's redundant_field_names lint rejects the starter's repeated names when warnings are denied.

Record does not implement Drop, which permits these direct moves of its non-Copy fields. Adding a Drop implementation would make those moves fail with E0509: the destructor needs a valid whole record. Copying an i64 field is different because it leaves the original field present. The absence of a Clone implementation on Record does not make its individual strings or vector unclonable; avoiding those clones is part of this exercise.

A passing submission must compile, pass the tests, and pass clippy -D warnings.