如何在编译时创建静态字符串

mhr*_*che 23 rust

我想创建一个&'static str由重复的字符序列组成的长片,例如abcabcabc...

在Rust中有没有办法通过表达式来实现这一点,例如long_str = 1000 * "abc"在Python中,或者我是否必须在Python中生成它并将其复制/粘贴到Rust代码中?

She*_*ter 14

你不能在稳定的Rust中做这样的事情.你的榜样1000 * "abc"就我理解Python而言,并不是在Python的"编译时"运行.

包括一个文件

如果它必须是静态的,您可以使用Cargo构建脚本.这是一些Rust代码,可以在实际编译代码之前做很多事情.具体来说,您可以编写一个包含您的字符串的源文件,然后使用include_str!它将其放入您的包中:

build.rs

use std::{
    env, error::Error, fs::File, io::{BufWriter, Write}, path::Path,
};

fn main() -> Result<(), Box<Error>> {
    let out_dir = env::var("OUT_DIR")?;
    let dest_path = Path::new(&out_dir).join("long_string.txt");
    let mut f = BufWriter::new(File::create(&dest_path)?);

    let long_string = "abc".repeat(100);
    write!(f, "{}", long_string)?;

    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

lib.rs

static LONG_STRING: &'static str = include_str!(concat!(env!("OUT_DIR"), "/long_string.txt"));
Run Code Online (Sandbox Code Playgroud)

延迟初始化

您可以创建一个lazy_static值,该值将使您的字符串只创建一次.这是在运行时完成的,但只需一次.

也可以看看:

遥远的未来

在某些时候,RFC 911将完全实现.此外,还有一些额外的RFC,每个都添加了新的功能,这将使您能够编写如下内容:

// Does not work yet!
static LONG_STR: String = "abc".repeat(1000);
Run Code Online (Sandbox Code Playgroud)

  • 现在有 [`str::repeat()`](https://doc.rust-lang.org/nightly/std/primitive.str.html#method.repeat),所以你可以写 `"abc"。 Repeat(100)` 用重复的数据生成一个 `String`。比 `iter::repeat()` 版本干净一点:) (2认同)

Luk*_*odt 12

有很多方法可以做到这一点.如果您愿意,可以从文件加载预先生成的字符串:

const DATA: &'static str = include_str!("filename.txt");
Run Code Online (Sandbox Code Playgroud)

或者在编译期间可以使用它 concat!:

const DATA: &'static str = concat!("abc", "abc");
Run Code Online (Sandbox Code Playgroud)

  • 我正在尝试创建一个"字符串乘法"宏,现在使用`concat!`20分钟......很遗憾,我很分心,我还没有成功:<...(还是!) (2认同)

Aki*_*oss 6

不为这个答案感到自豪:D,但我想给出不同的观点。

通过使用宏规则,您可以轻松地通过组合定义静态串联。在本例中,我定义 100 * str = 4 * 25 * str = 4 * 5 * 5 * str。您也可以用更少的行数(但更多的列:))执行 100 * str = 10 * 10 * str

macro_rules! rep {
    ($t:expr, 4) => { concat!($t, $t, $t, $t) };
    ($t:expr, 5) => { concat!($t, $t, $t, $t, $t) };
    ($t:expr, 25) => { rep!(rep!($t, 5), 5) };
    ($t:expr, 100) => { rep!(rep!($t, 25), 4) };
}


fn main() {
    assert_eq!(rep!("x", 100).len(), 100);
}
Run Code Online (Sandbox Code Playgroud)

由于宏适用于语言元素,因此不可能使用计数器并简单地递归调用宏,如下所示:

macro_rules! does_not_work {
    ($t:expr, 1) => { $t };
    ($t:expr, $n:) => { concat!($t, does_not_work!($t, $n-1)) };
}
Run Code Online (Sandbox Code Playgroud)

但在这个简单的情况下,递归地编写宏应该可以解决问题。我没有尝试使用不同的 Macro_rules 模式或其他类型的宏,但应该可以做一些更优雅的事情。