如何在Rust中构建一个str



假设变量c中有一个char,变量n中有一个正的int。我想构建包含c发生n次的str。我该怎么做呢?

我尝试将其构建为String,也许我只是在试图阅读字符串文档时感到头晕,但我看不出如何将其转换为str。但是,如果我试图直接将其构建为str,那么我也看不出如何做到这一点。

对于上下文,这里是我试图实现的完整功能。它接受一个字符串,并找到最长的连续字符序列(并通过取第一个出现的字符来打破联系)。

pub fn longest_sequence(s: &str) -> Option<&str> {
if s.len() == 0 { return None; }
let mut current_c = s.as_bytes()[0] as char;
let mut greatest_c = s.as_bytes()[0] as char;
let mut current_num = 0;
let mut greatest_num = 0;
for ch in s.chars() {
if current_c == ch {
current_num += 1;
if current_num > greatest_num {
greatest_num = current_num;
greatest_c = current_c;
}
} else {
current_num = 1;
current_c = ch;
}
}
// Now build the output str ...
}

我认为关于strString有一些误解。

  • str不能单独存在。它总是被用作&str(或Box<str>*str,但在你的情况下,这些不应该重要)。
  • &str不拥有任何数据。它仅仅是对另一个String的(部分)引用。
  • String实际上保存了数据。所以当你想返回data,使用String;如果要引用现有数据,返回&str.
  • Thereno way将本地String转换为&str。数据必须存储在某个地方,而&str不存储它。(为了完整起见:是的,您可以泄漏它,但这会在内存中创建一个永远不会再消失的永久字符串)

在你的例子中有两种方法:

  • 引用输入&str,因为它的数据已经存储在某个地方。
  • 返回String

作为旁注:不要做s.as_bytes()[0] as char,因为它将不起作用UTF8-strings。Rust字符串定义为UTF8。

这是一个可能的解决方案:

pub fn longest_sequence(s: &str) -> Option<&str> {
let mut current_c = s.chars().next()?;
let mut current_start = 0;
let mut current_len = 0;
let mut greatest: &str = "";
let mut greatest_len = 0;
for (pos, ch) in s.char_indices() {
if current_c == ch {
current_len += 1;
} else {
if greatest_len < current_len {
greatest = &s[current_start..pos];
greatest_len = current_len;
}
current_len = 1;
current_c = ch;
current_start = pos;
}
}
if greatest_len < current_len {
greatest = &s[current_start..];
}
Some(greatest)
}
pub fn main() {
let s = "🤪😁😁😁😉€€🤪🤪";
let seq = longest_sequence(s);
println!("{:?}", seq);
}
Some("😁😁😁")

一些解释:

  • 不需要检查空字符串。s.chars().next()?是自动的。
  • 使用s.chars().next()代替s.as_bytes()[0] as char,因为后者不兼容UTF8。
  • 我明确地存储greatest_len而不是使用greatest.len(),因为greatest.len()也不兼容UTF8,因为它给你字符串的大小字节字符。
  • 当找到相同值的新字符时,存储新的最大字符串;我必须将它移动到char类型改变的情况下(在循环之后),因为我们但是要知道当前字符的结尾。再次注意,&s[current_start..current_start+current_len]不能工作,因为&s[ .. ]需要索引字节,但current_len是在字符。所以我们需要等待另一个字符来知道前一个字符在哪里结束。

根据您的代码,另一个解决方案是:

pub fn longest_sequence(s: &str) -> Option<String> {
let mut current_c = s.chars().next()?;
let mut greatest_c = current_c;
let mut current_num = 0;
let mut greatest_num = 0;
for ch in s.chars() {
if current_c == ch {
current_num += 1;
if current_num > greatest_num {
greatest_num = current_num;
greatest_c = current_c;
}
} else {
current_num = 1;
current_c = ch;
}
}
// Build the output String
Some(std::iter::repeat(greatest_c).take(greatest_num).collect())
}
pub fn main() {
let s = "🤪😁😁😁😉€€🤪🤪";
let seq = longest_sequence(s);
println!("{:?}", seq);
}
Some("😁😁😁")

要将String转换为&'static str,您需要像这样泄漏它:

fn leak(s: String) -> &'static str {
let ptr = s.as_str() as *const str;
core::mem::forget(s);
unsafe {&*ptr}
}

AndchartoString:

fn cts(c: char, n: usize) -> String {
(0..n)
.map(|_| c)
.collect()
}

所以char&'static str基本上是这样的

fn conv(c: char, n: usize) -> &'static str {
leak(cts(c, n))
}

我不建议泄漏String,只是使用它。

最新更新