Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mismatched types: expected &str found String when assigning string

I'm trying to assign variable value (type String) based on the number of args:

let mut out_filename = "";
let args: Vec<_> = env::args().collect();
match args.len() {
    2 => out_filename = args[1],
    3 => out_filename = args[2],
    _ => panic!("To many params !"),
};

And I'm getting

src/main.rs:39:29: 39:36 error: mismatched types:
 expected `&str`,
    found `collections::string::String`
(expected &-ptr,
    found struct `collections::string::String`) [E0308]
src/main.rs:39         2 => out_filename = args[1],

How to make a match statement where the match value (1,2,3) is just a selector and the returned type is different? There is no let var = match ..

like image 373
MrSpock Avatar asked Apr 03 '16 00:04

MrSpock


2 Answers

You initialized out_filename with a string literal. The type of a string literal is &str (or, more specifically, &'static str), which is different from String.

The simplest solution is to assign out_filename to the result of the match expression directly:

use std::env;

fn main() {
    let args: Vec<_> = env::args().collect();
    let out_filename = match args.len() {
        2 => &args[1],
        3 => &args[2],
        _ => panic!("Too many params !"),
    };
}

[...] what if I wanted to make group of assignments based on args count like inside code block {} ? [...] Is there any way to get working code with basic match without let var = match { assign ?

You can simply put some let statements with no initializers before the match expression and initialize the variables as appropriate in each arm. You'll get a compiler error if you try to use a variable that might be left undefined and, unless you define the variables with let mut, you'll also get an error if you try to assign a variable more than once on a particular code path.

use std::env;

fn main() {
    let args: Vec<_> = env::args().collect();
    let out_filename;
    match args.len() {
        2 => out_filename = &args[1],
        3 => out_filename = &args[2],
        _ => panic!("Too many params !"),
    };
}
like image 124
Francis Gagné Avatar answered Nov 05 '22 21:11

Francis Gagné


As Francis Gagné mentioned, String and &str are not the same. The easiest way to convert them is to just use to_string(). It isn't always the best thing to do, but it will do while you are just learning because it will mostly work. You can read more about strings here.

let mut out_filename = "".to_string();
let args: Vec<_> = env::args().collect();
match args.len() {
    2 => out_filename = args[1].clone(),
    3 => out_filename = args[2].clone(),
    _ => panic!("To many params !"),
};

Note, I also fixed another error you would have come across, because of moving a value out of args. Explicitly cloning them, as I have done above, is one way of fixing that, and probably the easiest because you won't have to worry about lifetimes either.

like image 42
Peter Hall Avatar answered Nov 05 '22 22:11

Peter Hall