Skip to content

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

Easy Primitives

Field init shorthand and struct update syntax

Start with a host and port, apply overrides in input order, then return the final values joined by a colon.

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

Override rules

Key Behavior
host Replace the host with the value exactly as supplied.
port Replace the port if the value parses as u32; otherwise leave the current port unchanged.
Any other key Ignore the pair.

Keys are case-sensitive and are not trimmed. Later valid overrides replace earlier ones. An invalid port does not undo an earlier valid port override. An empty list leaves both base values unchanged.

Port parsing accepts ASCII decimal digits, optionally preceded by +, within 0..=4294967295. Leading zeros are allowed. Empty strings, negative signs, whitespace, underscores, hexadecimal notation and overflow are rejected. Use value.parse::<u32>() without trimming.

Hosts may be empty or contain spaces, colons or Unicode. Do not validate or normalize them. This is a string-and-integer exercise, not network-address validation: ports above 65535 are accepted if they fit in u32.

Format the result as host:port, with the port in ordinary decimal notation. For example, base ("localhost", 8080) and overrides [("host", "b.test"), ("port", "+002"), ("port", "bad")] produce "b.test:2". An empty host and port zero produce ":0".

Field shorthand and struct updates

Use a Config with host: String and port: u32. Practice rebuilding it after an override using struct update syntax. Assigning fields directly could produce the same output; the harness checks results rather than enforcing a particular syntax.

When a local variable and a field have the same name, Config { host, port } abbreviates Config { host: host, port: port }. To replace selected fields, list their new values and end with ..base for the remaining fields. The base expression comes last, without a trailing comma.

This complete example demonstrates both forms:

struct Config {
    host: String,
    port: u32,
}

fn main() {
    let host = String::from("localhost");
    let port = 8080;
    let base = Config { host, port };
    let updated = Config { port: 9000, ..base };

    assert_eq!(updated.host, "localhost");
    assert_eq!(updated.port, 9000);
    // The replaced field was not taken from the base.
    assert_eq!(base.port, 8080);
}

Which fields move?

Struct update uses the explicitly supplied values and moves or copies only the omitted fields from the base. Here host is omitted, so the new config takes ownership of base.host. The port field is explicitly replaced; it is not copied from base in this expression.

The starter tries to take base.host twice, producing E0382. After the first update, base.host is no longer available. Other initialized fields can still be accessed, but the partially moved base cannot be used as a whole value. Types implementing Drop have additional restrictions on moving out individual non-Copy fields.

If an omitted field is Copy, the update copies it and leaves it available in the base. Replacing the host while inheriting the port therefore keeps the old host usable:

struct Config {
    host: String,
    port: u32,
}

fn main() {
    let base = Config { host: "old.test".into(), port: 443 };
    let updated = Config { host: "new.test".into(), ..base };
    assert_eq!(updated.host, "new.test");
    assert_eq!(updated.port, 443);
    assert_eq!(base.host, "old.test");
    assert_eq!(base.port, 443);
}

Reference-valued fields can also be copied when their reference type is Copy, such as &str. Struct update does not require every struct to own all its data. This exercise uses an owned String, so carry one config forward through the override loop instead of repeatedly using an old base.

Cloning is another option when a type implements Clone, but it is not needed here. A derived clone of this config would clone its String too; the storage cost depends on the string rather than a fixed allocation charge for every use of struct update.

Apply one override at a time

Match key.as_str() against string literals. A literal pattern such as "host" is a &str pattern and cannot directly match a String value. For a host override, supply the new host and inherit the port. For a valid port override, supply the parsed port and inherit the host. On a parse error or unknown key, keep the current config.

Clippy's redundant_field_names flags repeated names that can use shorthand. needless_update flags an update where every field is already supplied, so the base contributes no fields. Fix these diagnostics rather than suppressing them. Submissions must compile, produce the expected output and pass the runner's Clippy checks.