Where is data stored in Rust generic functions?

Hello everyone

I'm learning Rust and trying to understand generics.
For example:

fn print_value<T>(value: T) {
    println!("{:?}", value);
}

Where is value stored in memory when the function is called? On the stack, heap, or does it depend on the type?

Where value gets stored has nothing to do with being generic. When you call print_value, Rust generates a new function "monomorphized" to that specific type, kind of like this:

print_value_i32(2_i32);

fn print_value_i32(value: i32) {
    println!("{:?}", value);
} 

So then, where value gets passed depends on the type. Sometimes it'll be be passed in registers, other times on the stack, and still other times the call will be inlined and it won't get "passed" anywhere. However, Rust will never automatically put things on the heap.

1 Like

value is always on the stack, it doesn't matter what type it is. The important thing is, if you call print_value, for example, with a String, then actually value will be a fat pointer to some data on the heap. But even if the actual data is on the heap, value (which is a pointer) is stored on the stack.

In general:

  • all variables (including function parameters) are stored in the stack (or sometimes, for small numbers, in the registers);
  • statics are stored in the static memory of the program
  • constants are inlined
  • you can get from something like std::alloc::alloc or Allocator::allocate a pointer to some memory on the heap, but even if it points to the heap, the pointer is stored on the stack.

When you call a function, the parameters are copied in the function's stack, so the value will always be on the stack:

use std::fmt::Display; // you were missing this

static NUM: u32 = 5; // stores 5 in the static memory of the binary
fn print_value<T: Display>(value: T) {
    println!("{value}");
}

fn main() {
    let s = String::from("Hello, world!"); // creates a pointer on the stack ('s') that points to the string "Hello, world!" on the heap
    let x = 7; // 7 is stored on the stack
    print_value(s); // the pointer is copied in a new stack frame (so it is on the stack)
    print_value(x); // the 7 is copied in a new stack frame (so it is on the stack)
    print_value(NUM); // the 5 is copied in a new stack frame, even if the original 5 wasn't on the stack (so it is on the stack)
}

I think that's a little confusing. It doesn't matter what value is, it's either on the stack or in registers (again, assuming the function isn't inlined). The fact that types like String may contain heap allocations is irrelevant.

If you'd like more information about ownership and where data lives, ask and ye shall receive. People around here have all sorts of really helpful links on the topic.

I think you thought I was asking the question but I was actually respoding. Anyway, I was saying that the only way to getting something on the heap was to allocate it and obtain a pointer, on the stack, to some memory on the heap. So a function parameter can never be on the heap

Is there a particular reason you're asking? (I'm wondering if this is an XY question.)

3 Likes

When I was setting up an HTTP request using the http crate and reading up a bit on how it works to retrieve the data in the request, I came across generic functions. I hadn’t read about that topic before, so I started looking into it and became concerned, since the goal is for the project to have a lot of v

How large is each individual v value? A few kilobytes?

How many copies of this value do you expect to have at the same time in a program? A million?