如何在没有 return 的情况下传递 &mut str 并更改原始 mut str?
How to pass &mut str and change the original mut str without a return?
我正在从书中学习 Rust,并且我正在处理第 8 章末尾的练习,但是我遇到了关于将单词转换为 Pig Latin 的问题。我想具体看看我是否可以将 &mut String
传递给接受 &mut str
的函数(也接受切片)并修改其中引用的字符串,以便将更改反射回外部而不需要一个 return
,就像在 C 中有一个 char **
.
我不太确定我是否只是搞砸了语法,或者由于 Rust 的严格规则我还没有完全掌握它是否比听起来更复杂。对于 to_pig_latin()
中的生命周期错误,我记得读过一些解释如何正确处理这种情况的东西,但现在我找不到它,所以如果你也能为我指出它,我将不胜感激。
另外,您如何看待我在字符串中处理字符和索引的方式?
use std::io::{self, Write};
fn main() {
let v = vec![
String::from("kaka"),
String::from("Apple"),
String::from("everett"),
String::from("Robin"),
];
for s in &v {
// cannot borrow `s` as mutable, as it is not declared as mutable
// cannot borrow data in a `&` reference as mutable
to_pig_latin(&mut s);
}
for (i, s) in v.iter().enumerate() {
print!("{}", s);
if i < v.len() - 1 {
print!(", ");
}
}
io::stdout().flush().unwrap();
}
fn to_pig_latin(mut s: &mut str) {
let first = s.chars().nth(0).unwrap();
let mut pig;
if "aeiouAEIOU".contains(first) {
pig = format!("{}-{}", s, "hay");
s = &mut pig[..]; // `pig` does not live long enough
} else {
let mut word = String::new();
for (i, c) in s.char_indices() {
if i != 0 {
word.push(c);
}
}
pig = format!("{}-{}{}", word, first.to_lowercase(), "ay");
s = &mut pig[..]; // `pig` does not live long enough
}
}
编辑:这是带有下面建议的固定代码。
fn main() {
// added mut
let mut v = vec![
String::from("kaka"),
String::from("Apple"),
String::from("everett"),
String::from("Robin"),
];
// added mut
for mut s in &mut v {
to_pig_latin(&mut s);
}
for (i, s) in v.iter().enumerate() {
print!("{}", s);
if i < v.len() - 1 {
print!(", ");
}
}
println!();
}
// converted into &mut String
fn to_pig_latin(s: &mut String) {
let first = s.chars().nth(0).unwrap();
if "aeiouAEIOU".contains(first) {
s.push_str("-hay");
} else {
// added code to make the new first letter uppercase
let second = s.chars().nth(1).unwrap();
*s = format!(
"{}{}-{}ay",
second.to_uppercase(),
// the slice starts at the third char of the string, as if &s[2..]
&s[first.len_utf8() * 2..],
first.to_lowercase()
);
}
}
I'm not quite sure if I'm just messing up the syntax or if it's more complicated than it sounds due to Rust's strict rules, which I have yet to fully grasp. For the lifetime errors inside to_pig_latin() I remember reading something that explained how to properly handle the situation but right now I can't find it, so if you could also point it out for me it would be very appreciated.
您尝试执行的操作行不通:使用可变引用,您可以就地更新裁判,但这在此处极为有限:
- a
&mut str
无法更改长度或任何相关内容
- a
&mut str
仍然只是一个参考,内存必须存在于某个地方,这里你在你的函数中创建新的字符串,然后尝试将它们用作参考的新后备缓冲区,作为编译器告诉你不起作用:字符串将在函数结束时被释放
您可以做的是使用 &mut String
,它可以让您就地修改拥有的字符串本身,这样更加灵活。而且,事实上,完全符合你的要求:一个 &mut str
对应一个 char*
,它是一个指向内存中某个位置的指针。
A String
也是一个指针,因此 &mut String
是指向内存中某个区域的双指针。
所以像这样:
fn to_pig_latin(s: &mut String) {
let first = s.chars().nth(0).unwrap();
if "aeiouAEIOU".contains(first) {
*s = format!("{}-{}", s, "hay");
} else {
let mut word = String::new();
for (i, c) in s.char_indices() {
if i != 0 {
word.push(c);
}
}
*s = format!("{}-{}{}", word, first.to_lowercase(), "ay");
}
}
您也可以通过使用更精细的方法来避免一些完整的字符串分配,例如
fn to_pig_latin(s: &mut String) {
let first = s.chars().nth(0).unwrap();
if "aeiouAEIOU".contains(first) {
s.push_str("-hay")
} else {
s.replace_range(first.len_utf8().., "");
write!(s, "-{}ay", first.to_lowercase()).unwrap();
}
}
虽然 replace_range
+ write!
的可读性不是很好,也不太可能是一个很大的收获,所以这也可能是 format!
,一些类似的东西的:
fn to_pig_latin(s: &mut String) {
let first = s.chars().nth(0).unwrap();
if "aeiouAEIOU".contains(first) {
s.push_str("-hay")
} else {
*s = format!("{}-{}ay", &s[first.len_utf8()..], first.to_lowercase());
}
}
我正在从书中学习 Rust,并且我正在处理第 8 章末尾的练习,但是我遇到了关于将单词转换为 Pig Latin 的问题。我想具体看看我是否可以将 &mut String
传递给接受 &mut str
的函数(也接受切片)并修改其中引用的字符串,以便将更改反射回外部而不需要一个 return
,就像在 C 中有一个 char **
.
我不太确定我是否只是搞砸了语法,或者由于 Rust 的严格规则我还没有完全掌握它是否比听起来更复杂。对于 to_pig_latin()
中的生命周期错误,我记得读过一些解释如何正确处理这种情况的东西,但现在我找不到它,所以如果你也能为我指出它,我将不胜感激。
另外,您如何看待我在字符串中处理字符和索引的方式?
use std::io::{self, Write};
fn main() {
let v = vec![
String::from("kaka"),
String::from("Apple"),
String::from("everett"),
String::from("Robin"),
];
for s in &v {
// cannot borrow `s` as mutable, as it is not declared as mutable
// cannot borrow data in a `&` reference as mutable
to_pig_latin(&mut s);
}
for (i, s) in v.iter().enumerate() {
print!("{}", s);
if i < v.len() - 1 {
print!(", ");
}
}
io::stdout().flush().unwrap();
}
fn to_pig_latin(mut s: &mut str) {
let first = s.chars().nth(0).unwrap();
let mut pig;
if "aeiouAEIOU".contains(first) {
pig = format!("{}-{}", s, "hay");
s = &mut pig[..]; // `pig` does not live long enough
} else {
let mut word = String::new();
for (i, c) in s.char_indices() {
if i != 0 {
word.push(c);
}
}
pig = format!("{}-{}{}", word, first.to_lowercase(), "ay");
s = &mut pig[..]; // `pig` does not live long enough
}
}
编辑:这是带有下面建议的固定代码。
fn main() {
// added mut
let mut v = vec![
String::from("kaka"),
String::from("Apple"),
String::from("everett"),
String::from("Robin"),
];
// added mut
for mut s in &mut v {
to_pig_latin(&mut s);
}
for (i, s) in v.iter().enumerate() {
print!("{}", s);
if i < v.len() - 1 {
print!(", ");
}
}
println!();
}
// converted into &mut String
fn to_pig_latin(s: &mut String) {
let first = s.chars().nth(0).unwrap();
if "aeiouAEIOU".contains(first) {
s.push_str("-hay");
} else {
// added code to make the new first letter uppercase
let second = s.chars().nth(1).unwrap();
*s = format!(
"{}{}-{}ay",
second.to_uppercase(),
// the slice starts at the third char of the string, as if &s[2..]
&s[first.len_utf8() * 2..],
first.to_lowercase()
);
}
}
I'm not quite sure if I'm just messing up the syntax or if it's more complicated than it sounds due to Rust's strict rules, which I have yet to fully grasp. For the lifetime errors inside to_pig_latin() I remember reading something that explained how to properly handle the situation but right now I can't find it, so if you could also point it out for me it would be very appreciated.
您尝试执行的操作行不通:使用可变引用,您可以就地更新裁判,但这在此处极为有限:
- a
&mut str
无法更改长度或任何相关内容 - a
&mut str
仍然只是一个参考,内存必须存在于某个地方,这里你在你的函数中创建新的字符串,然后尝试将它们用作参考的新后备缓冲区,作为编译器告诉你不起作用:字符串将在函数结束时被释放
您可以做的是使用 &mut String
,它可以让您就地修改拥有的字符串本身,这样更加灵活。而且,事实上,完全符合你的要求:一个 &mut str
对应一个 char*
,它是一个指向内存中某个位置的指针。
A String
也是一个指针,因此 &mut String
是指向内存中某个区域的双指针。
所以像这样:
fn to_pig_latin(s: &mut String) {
let first = s.chars().nth(0).unwrap();
if "aeiouAEIOU".contains(first) {
*s = format!("{}-{}", s, "hay");
} else {
let mut word = String::new();
for (i, c) in s.char_indices() {
if i != 0 {
word.push(c);
}
}
*s = format!("{}-{}{}", word, first.to_lowercase(), "ay");
}
}
您也可以通过使用更精细的方法来避免一些完整的字符串分配,例如
fn to_pig_latin(s: &mut String) {
let first = s.chars().nth(0).unwrap();
if "aeiouAEIOU".contains(first) {
s.push_str("-hay")
} else {
s.replace_range(first.len_utf8().., "");
write!(s, "-{}ay", first.to_lowercase()).unwrap();
}
}
虽然 replace_range
+ write!
的可读性不是很好,也不太可能是一个很大的收获,所以这也可能是 format!
,一些类似的东西的:
fn to_pig_latin(s: &mut String) {
let first = s.chars().nth(0).unwrap();
if "aeiouAEIOU".contains(first) {
s.push_str("-hay")
} else {
*s = format!("{}-{}ay", &s[first.len_utf8()..], first.to_lowercase());
}
}