`..` operator and constructors

The docs explain how you can use .. when instantiating structs:

struct Point3d {
    x: i32,
    y: i32,
    z: i32,
}

let mut point = Point3d { x: 0, y: 0, z: 0 };
point = Point3d { y: 1, .. point };

Why doesn't this operator work with structs of a different type?

struct Point3d {
    x: i32,
    y: i32,
}

let mut p2 = Point2d { x: 0, y: 0 };
let p3 = Point3d { z: 0, .. p2};

This produces an error regarding p2: expected struct `Point3d`, found struct `Point2d` .

Could someone explain why this work? Seems like the compiler should be able to do this ...

The old value is not dismantled by field and then put together, rather the syntax is just a shorthand for taking point, setting some of the fields on that value, then returning the resulting value.

So your first example is short-hand for

let mut point = Point3d { x: 0, y: 0, z: 0 };
point = {
    let new_value = point;
    new_value.y = 1;
    new_value
};

This desugaring clearly doesn't work if the types don't match.

2 Likes

If you're wondering why this is, it's because Rust doesn't do structural typing like that. Rust is designed so that the x y and z in Point3d are totally different from the x and y in Point2d. This is because although in your case they are very similar, the fields of types can mean different things depending on the context of the type. You wouldn't want to accidentally fill in inner on one type with a completely different type's inner for example. They likely serve a completely different purpose despite having the same name.

3 Likes