来自字符串引用参数的 Rust 可变字符串声明
Posted
技术标签:
【中文标题】来自字符串引用参数的 Rust 可变字符串声明【英文标题】:Rust mutable String declaration from String reference argument 【发布时间】:2021-02-23 13:11:59 【问题描述】:我有
fn main()
let x = String::from("12");
fun1(&x);
fn fun1(in_fun: &String)
let mut y = _______;
y.push_str("z");
println!("in fun ", y);
其中_____
是基于参数in_fun
声明y
的代码。
起初我尝试了let mut y = *in_fun;
错误move occurs because '*in_fun' has type 'String', which does not implement the 'Copy' trait
和let mut y = String::from(*in_fun);
也给出了同样的错误。
有效的是let mut y = String::from(format!("", *in_fun));
。
-
这是从
&String
声明可变String
的正确方法吗?
另外我还是不明白为什么用*
错误解引用&String
?我理解 *&
取消引用只返回引用的值。
【问题讨论】:
你必须clone这个字符串。请参阅The Rust Programming Language: Understanding Ownership 了解更多信息。let mut y = in_fun.clone()
有效,但 let mut y = *in_fun.clone()
无效。那不是我想克隆String
而不是&String
(在函数中传递的)。
in_fun.clone()
将克隆String
。 .clone()
方法通过引用获取 self
,因此 String
实现比克隆引用本身匹配得更好。
@kmdreko 但是in_fun
不是作为&String
而不是String
传递到函数中吗?被引用事物的方法是否也传递给引用(例如.clone()
)?还是您的意思是修改签名以改为使用String
?
“被引用事物的方法也传递给引用” - 通常,但它确实取决于函数签名(无论是 self
还是 &self
) 以及可用的其他选项。考虑查看this Q&A,它讨论了如何推导函数查找。
【参考方案1】:
&String
是一个不可变的引用。 Rust 对此非常严格,可以防止人们经常遇到的许多常见事故。取消引用 &String 是不可能的,因为它会破坏 rust 的安全保证,允许您修改只有读取权限的位置。请参阅ownership explanation。
该函数应该接受一个可变引用&mut String
(然后可以就地修改字符串)或者它需要.clone()
来自不可变引用的字符串。
采用可变引用比克隆更有效,但它限制了调用者以不可变的方式并行共享它。
如果您只想打印一些附加信息,我知道的最好方法是:
fn fun1<S: std::fmt::Display>(in_fun: S)
println!("in fun z", in_fun);
fn main()
let mut x = String::from("12");
fun1(&x);
fun1(&mut x);
fun1(x);
fun1("12");
我使用 Display
特征,所以任何实现都可以。见playground。
另一方面,如果你真的需要一个拥有的字符串,那么就要求吧:)
fn fun1<S: Into<String>>(in_fun: S)
let mut y = in_fun.into();
y.push('z');
println!("in fun ", y);
fn main()
let x = String::from("12");
fun1(&x);
fun1(x);
fun1("12");
这样您可以同时接受 &str 和 String 并保持高效,尽可能避免克隆。
【讨论】:
这个let mut y = in_fun.into();
会隐式克隆吗?
@C14L,不是String
,对于相同的类型,它是一个标识函数doc.rust-lang.org/src/core/convert/mod.rs.html#552-556,否则它取决于Into/From的实现。 &str
必须被克隆。
有趣。但是,改变y
不会改变in_fun
也指向的相同数据吗?
啊,我的印象是引用&
和取消引用*
之间的关系就像函数和反函数,s.t. f^-1(f(x)) = *&x
@C14L,如果它是一个拥有的值,就像String
,那么它会是可以的,因为除了当前范围之外没有其他人可以访问,String
无法访问任何其他方式(安全)。如果参数是&str
,.into()
将克隆它,这样就可以了。【参考方案2】:
首先是工作代码:
fn fun1(in_fun: &String)
let mut y = in_fun.clone();
y.push_str("z");
println!("in fun ", y);
或者,您的直觉告诉您必须取消引用,因此 (*in_fun).clone()
的工作原理相同,但有点多余。 *in_fun.clone()
NOT 有效,因为它等同于 *(in_fun.clone())
(取消引用克隆),这不是您想要的。在调用clone
之前不需要取消引用引用的原因是因为Rust's method resolution 允许您调用类型的方法或使用对该类型的引用访问类型的属性,而.clone
有一个@987654328 @接收者。
let mut y = *in_fun
不起作用的原因是因为它试图将字符串从引用下方移出,这不起作用。
【讨论】:
我没有意识到.clone()
出现在*
之前,我以为优先级只是从左到右。以上是关于来自字符串引用参数的 Rust 可变字符串声明的主要内容,如果未能解决你的问题,请参考以下文章
python中变量的引用、可变和不可变类型、局部变量和全局变量