Trying to understand moving ownership of vectors to funcs

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?

Please use code blocks (``` on a line before and after) to format your code snippets and compiler errors:

Otherwise it's hard for us to read.

1 Like

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:

fn parse_config(args: Vec<String>) -> Config
1 Like

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.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.