-3

I have a vector of strings and a method that is accepting [&str]. When I provide the strings as string literals everything works however when I try to build the same vector dynamically using Strings everything is failing.

Examples below:

//everything works fine.
let imports = vec!["import 1", "import 2"];
let import_selector = gtk::DropDown::from_strings(&imports);

//Throws an error
let mut imports = Vec::new(); // ive tried specifying the type here as Vec<&str> but it didn't help.
    for imp in app_settings.lock().unwrap().imports.clone() {
        let name = match imp.clone() {
            Some(name) => name,
            None => continue
        };

        if !imports.contains(&name) {
            imports.push(name.as_str()); //I've tried this as &name giving the same result.
        }
    }

let import_selector = gtk::DropDown::from_strings(&imports);
//throws error: expected slice `[&str]`, found struct `Vec`

I think this is something to do with how I am passing the strings into the vector as I am passing String and not a string literal however the Vector.push method seems to only accept String.

How do I go about fixing this?

Adding a working example to demonstrate this issue:

use gtk::prelude::*;
use gtk::{CssProvider, StyleContext, Orientation};
use gtk::gdk::Display;
use libadwaita::{Application, ApplicationWindow};
use std::path::{Path, PathBuf};
use std::thread;
use std::fs;
use std::time::Duration;

const APP_ID: &str = "org.gtk_rs.HelloWorld2";

fn main() {
    let app = Application::builder().application_id(APP_ID).build();
    app.connect_activate(build_ui);
    app.run();
}

pub fn build_ui(app: &Application) {
    let imports = vec!["import 1", "import 2"];
    let import_selector = gtk::DropDown::from_strings(&imports);

    let imports_as_strings = Vec::new();
    imports_as_strings.push(String::from("import 1"));
    imports_as_strings.push(String::from("import 2"));
    
    //Throws an error
    let mut imports_2 = Vec::new(); // ive tried specifying the type here as Vec<&str> but it didn't help.
        for imp in imports_as_strings {
            if !imports_2.contains(&imp) {
                imports_2.push(imp); //I've tried this as &name giving the same result.
            }
        }
    
    let import_2_selector = gtk::DropDown::from_strings(&imports_2);
    //throws error: expected slice `[&str]`, found struct `Vec`

    let new_box = gtk::Box::builder()
        .orientation(Orientation::Vertical)
        .build();

    new_box.append(&import_selector);
    new_box.append(&import_2_selector);

    let window = ApplicationWindow::builder()
        .application(app)
        .title("My GTK App")
        .build();

    // Present window
    window.present();
}
John554
  • 145
  • 1
  • 7
  • What version of Rust are you using? `Vec` derefs to a slice, and that deref coercion should be kicking in automatically in this case on any recent version of Rust. – Silvio Mayolo Apr 28 '23 at 04:17
  • Currently running rustc 1.66.0 (69f9c33d7 2022-12-12) – John554 Apr 28 '23 at 04:47
  • Error: unresolved import `adw`, it's not on crates.io, what is it? Please read through the [mre] article and build a new project from the ground up only including the necessary parts, your imports are a mess, too. – cafce25 Apr 28 '23 at 04:48
  • It's libadwaita `adw = { version = "0.2.1", package = "libadwaita", features = ["v1_2"] }` – John554 Apr 28 '23 at 04:50
  • Please also don't add necessary information as comments, add them to the question instead. – cafce25 Apr 28 '23 at 04:51

1 Answers1

0

I wasn't able to reproduce your issue, but I'm guessing you aren't actually trying this with as_str and instead adding a reference. When you do that, you create a Vec<&String> instead of a Vec<&str>. If you simply add the type on this line:

let mut imports_2: Vec<&str> = Vec::new();

then you can guarantee this Vec will always deref to &[&str] This will move your error elsewhere, or allow type inference to fix it.

You can push &String or &str values and they will be deref-ed to &str. If you try to push String, you will be told to add a reference.

imports.push(&name);

Doing as_str should always work.

imports.push(name.as_str());
drewtato
  • 6,783
  • 1
  • 12
  • 17