Skip to content

← Shape Your Data: Structs, Enums, Pattern Matching step 2 of 26

Easy Primitives

Field init shorthand and struct update syntax

Start from a base configuration and apply a list of (key, value) overrides in order, then render the result as "host:port".

pub fn apply_overrides(
    base_host: String,
    base_port: u32,
    overrides: Vec<(String, String)>,
) -> String

Recognised keys are "host" and "port". Anything else is ignored. A "port" value that does not parse as a u32 is ignored too. Later overrides win over earlier ones. An empty override list gives back the base.

With base ("localhost", 8080) and overrides [("host", "b.test"), ("port", "2"), ("host", "c.test")] the answer is "c.test:2".

The two pieces of syntax

Field init shorthand. When the variable already has the field’s name, you write the name once:

let port = 443;
let cfg = Config { host, port };     // not `host: host, port: port`

This is not a style preference you can decline. redundant_field_names is on by default, and under -D warnings it fails your build.

Struct update syntax. ..other fills in every field you did not list:

let tweaked = Config { port: 9000, ..base };

It must come last and takes no trailing comma.

..base is not a JavaScript spread

This is the whole reason the item exists. {...base, port: 9000} in JavaScript copiesbase is untouched and reusable. ..base in Rust moves. It takes the remaining fields out of base and hands them to the new value, and any field it takes that is not Copy is gone from base afterwards.

The starter ships the demonstration: two configs built from one base. It does not compile. Read the message before you change anything —

error[E0382]: use of moved value: `base.host`

Note what rustc says and what it does not say. It does not complain about base.port: u32 is Copy, so ..base copied it and left the original in place. Only host, a String, actually moved. Rust tracks ownership per field, which is why the error is about base.host and not about base. This granularity is real and useful — you can move one field out of a struct and keep using the others.

Three ways out, in rough order of how often you want them:

  1. Thread one value through. Build each successive config from the previous one, so nothing is used twice. That is what this problem wants.
  2. Clone. ..base.clone() works and costs an allocation per use.
  3. Borrow instead of own. Not available here — struct update always moves.

Another lint to know about

needless_update fires when you list every field and then also write ..base. At that point the base contributes nothing, and clippy tells you to delete it. It is on by default.

Shape of a solution

You want a Config { host: String, port: u32 }, one value of it, and a loop over the overrides that rebuilds it. Matching on key.as_str() gives you &str arms, which is what string literals compare against — match key { "host" => ... } on a String will not type-check.

Remember the grade is compile + tests + clippy -D warnings.

Loading visualization…