【问题标题】:How to convert a String into a &'static str如何将字符串转换为 &'static str
【发布时间】:2014-05-31 23:30:45
【问题描述】:

如何将String 转换为&str?更具体地说,我想将其转换为具有 static 生命周期 (&'static str) 的 str

【问题讨论】:

  • 这似乎既不可能也不可取。 'static 生命周期意味着字符串永远不会被释放,即内存泄漏。为什么你需要&'static str 而不是&'a str 来获得一些合适的'a
  • 那么将其转换为&'a str 会怎样?
  • 通过as_slice。如果您描述了您正在尝试解决的具体问题以及您在此过程中遇到的问题,将会更容易提供帮助。
  • 另请注意SendStr,这是一个拥有的字符串或静态字符串的类型。

标签: rust


【解决方案1】:

为 Rust 1.0 更新

您无法从String 获得&'static str,因为Strings 可能不会在您的程序的整个生命周期中都存在,这就是&'static 生命周期的含义。您只能从中获取由String 自己的生命周期参数化的切片。

要从 String 转到切片 &'a str,您可以使用切片语法:

let s: String = "abcdefg".to_owned();
let s_slice: &str = &s[..];  // take a full slice of the string

或者,您可以使用 String 实现 Deref<Target=str> 并执行显式重借:

let s_slice: &str = &*s;  // s  : String 
                          // *s : str (via Deref<Target=str>)
                          // &*s: &str

还有另一种方法可以实现更简洁的语法,但只有在编译器能够确定所需的目标类型(例如在函数参数或显式类型的变量绑定中)时才能使用它。它被称为deref coercion,它只允许使用&amp; 运算符,编译器会根据上下文自动插入适量的*s:

let s_slice: &str = &s;  // okay

fn take_name(name: &str) { ... }
take_name(&s);           // okay as well

let not_correct = &s;    // this will give &String, not &str,
                         // because the compiler does not know
                         // that you want a &str

请注意,此模式对于String/&amp;str 不是唯一的 - 您可以将其用于通过Deref 连接的每一对类型,例如CString/CStr 和@987654343 @/OsStr 来自std::ffi 模块或PathBuf/Path 来自std::path 模块。

【讨论】:

  • 在 Rust 1.10 而不是 let s_slice: &amp;str = &amp;s[..]; 你可以简单地这样做:let s_slice: &amp;str = s.as_str();
  • 有时,原始字符串不够活跃,就像在 match {...} 块中一样。这将导致's' does not live long enough error
  • 关于如何在&amp;strString&amp;[u8]Vec&lt;u8&gt; 之间转换的更一般的答案可以找到here
  • 这个答案很完美?
【解决方案2】:

你可以这样做,但它涉及泄露String的内存。这不是你应该轻易做的事情。通过泄漏String 的内存,我们保证永远不会释放内存(因此泄漏)。因此,对内部对象的任何引用都可以解释为具有'static 生命周期。

fn string_to_static_str(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

fn main() {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    let s: &'static str = string_to_static_str(s);
}

【讨论】:

  • String 保证,只要对象没有被删除,内存就会保持活动状态。由于mem::forget 保证对象永远不会被丢弃,我们保证对包含的str 的引用永远不会无效。因此我们可以断言它是一个'static 引用
  • 这对我的 Rust 应用程序非常有用,它需要将 String 强制转换为 &amp;'static str,以便从原始 String 创建的令牌可以在所有线程中使用。如果没有这个,Rust 编译器会抱怨我的 String 的生命周期在 main 函数结束时结束,这还不够好,因为它没有 'static 保证。
  • @mmstick:在这种情况下,更好的解决方案是使用crossbeam 和作用域线程
  • @ker:应用程序需要字符串在应用程序的整个生命周期中都存在,所以我认为这不是更好的解决方案。还有从该字符串生成的令牌,要求原始字符串具有静态生命周期才能跨线程共享。
  • @mmstick:如果您将整个应用程序放入一个横梁范围并在范围之外创建字符串,那么您将得到准确的结果。
【解决方案3】:

从 Rust 1.26 版开始,可以在不使用 unsafe 代码的情况下将 String 转换为 &amp;'static str

fn string_to_static_str(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

这会将String 实例转换为装箱的str 并立即泄露它。这将释放字符串当前可能占用的所有多余容量。

请注意,几乎总是有比泄漏对象更可取的解决方案,例如如果您想在线程之间共享状态,请使用 crossbeam crate。

【讨论】:

  • 我遇到的一个用例是clap。我正在创建一个参数,它指定要使用多少个线程,默认值等于用户机器上的逻辑核心数。 Arg::default_value 采用 &amp;str 并仅保留此引用,这通常很好,因为通常此值是编译时常量。但在这种情况下并非如此,这意味着我需要在运行时创建一个&amp;'static str。这是我的问题的确切解决方案。
【解决方案4】:

TL;DR:您可以从 String 获得 &amp;'static str,而 String 本身具有 'static 生命周期。

虽然其他答案是正确且最有用的,但有一个(不太有用)边缘情况,您确实可以将String 转换为&amp;'static str

引用的生命周期必须总是短于或等于被引用对象的生命周期。 IE。被引用对象的寿命必须比引用长(或等于长)。由于'static 表示程序的整个生命周期,因此不存在更长的生命周期。但是相等的寿命就足够了。因此,如果String 的生命周期为'static,您可以从中获取&amp;'static str 引用。

const fn 功能发布时,理论上可以使用Rust 1.31 创建String 类型的static。不幸的是,目前唯一返回 String 的 const 函数是 String::new(),而且它仍然在功能门之后(所以现在需要 Rust nightly)。

因此,以下代码进行了所需的转换(每晚使用)...实际上没有任何实际用途,除了完整地表明在这种边缘情况下它是可能的。

#![feature(const_string_new)]

static MY_STRING: String = String::new();

fn do_something(_: &'static str) {
    // ...
}

fn main() {
    do_something(&MY_STRING);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-18
    • 1970-01-01
    • 2011-12-31
    相关资源
    最近更新 更多