1

I am receiving an &str from the application's args, but I need this value as &'static &str. How can I convert it?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7ab020528a0d3e26a49b915542f50c8e

fn fun(var: &'static &str) {}

fn main() {
    let var: &str = "temp";
    fun(var);
}
error[E0308]: mismatched types
   --> src/main.rs:102:9
    |
102 |         matches.value_of("STATIC-FILES").unwrap(),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &str, found str
    |
    = note: expected type `&'static &str`
               found type `&str`

error: aborting due to previous error

@more information

.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── main.rs
│   └── server.rs
// file: main.rs
extern crate clap;

use clap::{App, Arg};

mod server;

fn main() {
    let app = App::new("My App")
    .arg(
            Arg::with_name("STATIC-FILES")
                .help("Sets absolute path to client's static files")
                .default_value("/var/www/client"),
        )

    let matches = app.get_matches();

    let s = server::start(
        matches.value_of("STATIC-FILES").unwrap(),
    );
// file: server.rs
use actix_files as fs;
use actix_web::{guard, web, App, HttpResponse, HttpServer};

pub fn start(
    static_files_path: &'static &str,
) -> io::Result<()> {

    let sys = actix_rt::System::new("myappsvr");

    HttpServer::new(move || {
        let sfp = move || static_files_path;
        App::new()
            .service(fs::Files::new("/", sfp()).index_file("index.html"))
    })

    (...)

    .start();

    sys.run();
}

In main.rs I am starting an HTTP server (Actix). The path to the directory with static files has to be passed as an argument.

App::new().service(fs::Files::new("/", sfp()).index_file("index.html")) requires &'static &str in place of sfp().

mfluehr
  • 2,832
  • 2
  • 23
  • 31
Piotr Płaczek
  • 530
  • 1
  • 8
  • 20
  • 1
    I would expect you can do this the opposite way, but can't really turn a "dynamic" value into something available statically. – Bartek Banachewicz Dec 12 '19 at 12:25
  • that not possible you need a `&'static &'static str` – Stargateur Dec 12 '19 at 12:26
  • 7
    Sounds like this might be an XY problem. Why do you need a `&'static &str`? – justinas Dec 12 '19 at 12:35
  • 1
    The question code can be fixed by making a small change: `let var = &"temp";` However I assume this will not work for your actual code, which is why we need more information. – trent Dec 12 '19 at 13:07
  • @trentcl I was trying to find some information about that, is it transferring the first borrow's lifetime to the second borrow?(&&str) Which makes sense but i couldn't find any reference about the case. – Ömer Erden Dec 12 '19 at 13:19
  • 1
    @ÖmerErden `"temp"` is a const rvalue, which means it's subject to [static promotion](https://stackoverflow.com/questions/50345139/why-can-i-return-a-reference-to-a-local-literal-but-not-a-variable). You can take as many `&` references as you want to a literal and as long as you don't coerce them shorter they will all have the `'static` lifetime. [Example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ef3170da54b6db03083f5ab6ec84eb84) – trent Dec 12 '19 at 13:47
  • @trentcl looking for this thanks ! And i guess this looks like an answer for this question. – Ömer Erden Dec 12 '19 at 14:04
  • 1
    Definitely looks like an X/Y problem. [`fs::Files::new`](https://docs.rs/actix-files/0.2.0-alpha.3/actix_files/struct.Files.html#method.new) does *not* require its argument to be `'static`; That would be weird. – mcarton Dec 12 '19 at 14:36
  • Maybe it helps to have `fun` accept a `String`? – phimuemue Dec 12 '19 at 21:32

1 Answers1

4

When the compiler says you need &'static, it doesn't really mean that. It's trying to tell you that temporary references are not allowed here.

&'static str is a special case that is basically a leaked memory. In 99.99% of cases it's a bad idea to leak memory, so compiler's suggestion is stupid. Don't try to use &'static str. Use an owned String instead.

Keep in mind that &str is not a string by itself, but a read-only view of some string stored elsewhere.

So the real problem is that you've used a temporary &str, and you should have used a permanently stored String instead.


But for the 0.01% of cases where you can leak memory of a string, here's how:

let leaked: &'static str = Box::leak("hi".to_string().into_boxed_str());
Kornel
  • 97,764
  • 37
  • 219
  • 309