假设变量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 ...
}
我认为关于str
和String
有一些误解。
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}
}
Andchar
toString
:
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
,只是使用它。