I think there are a couple of misconceptions about str
vs String
.
str
can never exist alone. It is always used as &str
(or Box<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) another String
.
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 = "€€";
let seq = longest_sequence(s);
println!("{:?}", seq);
}
Some("")
Some explanations:
- No need to check for empty string.
s.chars().next()?
does so automatically.
- Use
s.chars().next()
instead of s.as_bytes()[0] as char
, as the second one is not UTF8 compatible.
- I explicitely store
greatest_len
instead of using greatest.len()
because greatest.len()
is also not UTF8 compatible as it gives you the size of the string in bytes, not in chars.
- You stored the new largest string whenever a new char of the same value was found; I had to move it to the case where the char type changed (and once after the loop), because we don't yet know the end of the current char. Again, note that
&s[current_start..current_start+current_len]
wouldn't work, because &s[ .. ]
wants indices in bytes, but current_len
is in chars. So we need to wait for another char to know where the previous one ended.
Another solution, based on your code, would be:
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("")