Suppose I have a char
in the variable c
and a positive int
in the variable n
. I want to build the str
containing c
occurring n
times. How can I do it?
I tried building it as a String
, and maybe I just got dizzy trying to read the documentation on strings, but I couldn't see how to convert it to a str
. But then if I'm trying to just build it as a str
directly then I couldn't see how to do that either.
For context, here is the full function I'm trying to implement. It takes a string and finds the longest sequence of consecutive characters (and breaks ties by taking the first that occurs).
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 ...
}
CodePudding user response:
I think there are a couple of misconceptions about str
vs String
.
str
can never exist alone. It is always used as&str
(orBox<str>
or*str
, but in your case those shouldn't matter).&str
does not own any data. It is merely a reference to (parts of) anotherString
.String
actually holds data.- So when you want to return data, use
String
; if you want to reference existing data, return&str
. - There is no way to convert a local
String
to a&str
. Somewhere the data has to be stored, and&str
doesn't store it. (for completeness sake: Yes you could leak it, but that would create a permanent string in memory that will never go away again)
So in your case there are two ways:
- Reference the input
&str
, because somewhere its data is already stored. - Return a
String
instead.
As a side note: do not do s.as_bytes()[0] as char
, as it will not work with UTF8-strings. Rust strings are defined as UTF8.
Here is one possible solution:
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 = "