I am just starting with Rust and decided to read the (rather excellent) Rust Book, and in chapter 12 there is a Command Line Program tutorial.
In that chapter I got to the point where the program reads from args, stores values in a Vector, and puts vector values in a struct (through a function):
use std::env;
use std::fs;
fn main() {
let args: Vec<String> = env::args().collect();
let config = parse_config(&args);
println!("Searching for {}", config.query);
println!("In file {}", config.filename);
let contents =
fs::read_to_string(config.filename).expect("Something went wrong reading the file");
println!("With text:\n{}", contents);
}
struct Config {
query: String,
filename: String,
}
fn parse_config(args: &[String]) -> Config {
let query = args[1].clone();
let filename = args[2].clone();
Config { query, filename }
}
So I thought to myself: I might as well just pass ownership of the vector to the function, since I don´t intend to use the vector anymore in main (I will just need the struct), so I changed function signature to:
fn parse_config(args: [String]) -> Config
(changing function call to let config = parse_config(args);)
But now the compiler gives an error:
the size for values of type `[std::string::String]` cannot be known at compilation time
doesn't have a size known at compile-time
help: the trait `std::marker::Sized` is not implemented for `[std::string::String]`rustc(E0277)
So, what is this error about and am I allowed to pass a vector (not its reference, but the vector itself, giving ownership) to a function?
You aren't passing the vector there, you are passing a slice of String values, written [String], which just represents a sequence of String values. Since the length of that sequence cannot be known at compile time, Rust generally needs it to be behind some kind of pointer, such as an & reference or a Box, hence the error.
In your case, to pass ownership of the vector you want:
To pass ownership the argument should be args: Vec<String>, or if you want to pass a slice, then args: Box<[String]>.
& passes by reference, but is temporarily borrowed and tied to a single scope.
Box passes by reference, owned.
Vec passes by reference, owned, and can grow.
You can't pass slice's data by value (args: [String]), because the length isn't stored in the slice itself, but only in the reference to the slice (in the & or Box or Vec). You can pass compile-time fixed-length arrays by value, like args: [String; 10], but that really must be hardcoded length, it can't be [String; n]. There's no reason to pass by value here though.