I have some experience in C, but I'm new to Rust. What happens under the hood when I pass a struct into a function and I return a struct from a function? It seems it doesn't "copy" the struct, but if it isn't copied, where is the struct created? Is it in the stack of the outer function?
struct Point {
x: i32,
y: i32,
}
// I know it's better to pass in a reference here,
// but I just want to clarify the point.
fn copy_struct(p: Point) {
// Is this return value created in the outer stack
// so it won't be cleaned up while exiting this function?
Point {.. p}
}
fn test() {
let p1 = Point { x: 1, y: 2 };
// Will p1 be copied or does copy_struct
// just use a reference of the one created on the outer stack?
let p2 = copy_struct(p1);
}
We can pass a struct to a function by specifying the struct name as the type in the parameter list. We can return a struct from a function by specifying the struct name as the return type. We can define functions that are specific to a struct, called methods, that can only be used by instances of that struct.
Rust uses a feature called traits, which define a bundle of functions for structs to implement. One benefit of traits is you can use them for typing. You can create functions that can be used by any structs that implement the same trait.
To get a specific value from a struct, we use dot notation. For example, to access this user's email address, we use user1. email . If the instance is mutable, we can change a value by using the dot notation and assigning into a particular field.
A type that is composed of other types. Structs in Rust come in three flavors: Structs with named fields, tuple structs, and unit structs. Regular structs are the most commonly used. Each field defined within them has a name and a type, and once defined can be accessed using example_struct.
As a long time C programmer also playing with Rust recently, I understand where you're coming from. For me the important thing to understand was that in Rust value vs reference are about ownership, and the compiler can adjust the calling conventions to optimize around move semantics.
So you can pass a value without it making a copy on the stack, but this moves the ownership to the called function. It's still in the calling functions stack frame, and from a C ABI perspective it's passing a pointer, but the compiler enforces that the value is never used again upon return.
There's also return value optimization, where the calling function allocates space and the pointer is passed to the caller which can fill out the return value there directly. This is the sort of thing a C programmer would be used to handling manually.
So the safety of the ownership rules and borrow checker, combined with the lack of a fixed guaranteed ABI/calling convention, allow the compiler to generate efficient call sites. And generally you worry more about ownership and lifetime, then needing to try and be clever about function call stack behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With