I'm doing the rustlings exercises and I tried this to make a capitalize function. But the join part does not work. It says:
"the method join
exists for struct Vec<char>
, but its trait bounds were not satisfied
the following trait bounds were not satisfied:
<[char] as Join<_>>::Output = _
"
which I don't know what means. What would be the right way to join a char vector?
pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => {
let upper = first.to_ascii_uppercase();
let mut v = c.collect::<Vec<char>>();
v[0] = upper;
v.join("")
},
}
}
CodePudding user response:
To answer your question, the best way to get a string from a vec of chars is to iter and collect:
let my_string = my_char_vec.iter().collect();
But there are other problems in your code:
- you're taking the first char to check the string isn't empty, then you build a string from the rest of the iteration, and you make the first char replace the first char of that string... losing this char which was the second one of the initial str
- you're building a useless vec and iterating again. Those are expensive steps that you don't need
You can fix those problems by adapting the code to directly write from the iteration into the string:
pub fn capitalize_first(input: &str) -> String {
let mut chars = input.chars();
let mut string = String::new();
if let Some(first) = chars.next() {
string.push(first.to_ascii_uppercase());
for c in chars {
string.push(c);
}
}
string
}
Note that you're using a function dedicated to ASCII characters. This is fine when you're sure you're only dealing with ASCII but it's generally safer to use to_uppercase
.
If you're sure you can use to_ascii_upercase
, then there's another solution.
Because ASCII chars have the same size in bytes in lowercase and uppercase, you can change them in place in the UTF8 string:
pub fn capitalize_first(input: &str) -> String {
let mut string = input.to_string();
if !string.is_empty() {
string[..1].make_ascii_uppercase();
}
string
}
This second approach could be used on a mutable string with zero allocation.
CodePudding user response:
There's a constraint in the return type of the join
method that the char
type does not meet, since it doesn't have a static lifetime:
pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
where
Self: Join<Separator>,
{
Join::join(self, sep)
}
You should use String::from_iter
instead:
pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => {
let upper = first.to_ascii_uppercase();
let mut v = c.collect::<Vec<char>>();
v[0] = upper;
String::from_iter(v)
},
}
}