Another title to my question could read "Stack and heap – a beginners approach". I’ve a function that needs to read through an array of Strings. The parameter’s type could be
[String]
&[String]
&[&str]
From my understanding variant three &[&str] is best way to go with minimal stack-consumption for there are solely pointers stored on stack which will be the least memory-consumption.
Am I right?
Can I make the same assumption about runtime, for this runtime is partly a result of the copy-operations?
If you have an array or vector of Strings and want your function to read its contents but not consume it, &[String] would be the best option. &[&str] would require you to create a new array or vector with references to the elements of the already existing one.
[T] is not a valid parameter, and it's mostly unusable as a type, because it has no length. The length of slices is stored in the "fat" reference (in the & part).
&[T] parameter is passed and used exactly the same for all types of T.
In most cases parameters are passed in registers, not even via the stack. The contents of a borrowed slice will never be copied when passed around. A slice argument is just pointer and a length, literally two integers, so it's cheap to pass around.
There is a difference between &str and String, but it's not directly related to the stack. It's true that String stores its data on the heap, but that doesn't mean that non-String types would use the stack.
&str is completely agnostic about where its data comes from. You can't directly allocate &str anywhere. It's not a string! It's a temporary permission to view some other string type. That other thing it is borrowing from could be a String, or could be other data stored anywhere. It could come from an on-stack ArrayString, or could be hardcoded into the executable, or could be a sub-slice of a completely different string type.
In practical terms:
&[String] forces the caller to have String allocated, so the caller has to make heap-based Strings even if they use a different string type.
&[&str] is physically different in memory than &[String], so if the caller has &[String], they will now need to allocate Vec<&str> to borrow all the strings, and lend you the Vec as &[&str].
None are ideal. If it's in internals of your own program, just use the type that fits what the callers of your function already have.
If it's a public API and you want to offer flexibility:
&[impl AsRef<str>] is relatively simple to use. It will generate a separate copy of your function for every string-like type it's used with.
impl Iterator<Item = &str> is most flexible, since it allows providing strings from any data source without allocating any particular type.