我遇到了这个问题。我的代码如下所示:
struct MyStruct {
name:String
}
impl MyStruct {
fn foo(&mut self) {
self.name = "Bob";
self.bar(self, "Foo");
}
fn bar(&mut self, my_struct: MyStruct, last_name: String) {
self.name = format!("{} {}", my_struct.name, last_name)
}
}
但是,我在error: mismatched types: expected 'MyStruct', found '&mut MyStruct' (expected struct MyStruct, found &-ptr)
方法中收到此错误foo
。我知道Rust还没有达到它的1.0版本,但是我想了解Rust中的指针。
我做错了什么以及其他一些解决方法?
我尝试过的事情:
let f = *self;
self.bar(f, "Foo"); // works using the "raw pointer"
self.bar(*self, "Foo"); // doesn't work.. Error message: "borrow of `*self` occurs here"
生锈版:rustc 0.12.0-pre-nightly (09abbbdaf 2014-09-11 00:05:41 +0000)
答案 0 :(得分:1)
您的代码中存在两个问题。
第一个是你的字符串的一个小问题。当您键入"Bob"
时,它的类型为&'static str
,而您希望代码中至少某些位置显示String
。将"Bob"
替换为"Bob".to_string()
即可轻松解决此问题。
第二个问题是,你实际上是在尝试两次为函数赋予相同的值。你可以在生锈中做到这一点,但你需要非常小心你是如何做到的。
最简单的修复方法是克隆对象,从而提供两个不同(但相等)的对象。在这种情况下,您的示例是:
#[deriving(Clone)]
struct MyStruct {
name:String
}
impl MyStruct {
fn foo(&mut self) {
self.name = "Bob".to_string();
let cloned = self.clone();
self.bar(clone, "Foo".to_string());
}
fn bar(&mut self, my_struct: MyStruct, last_name: String) {
self.name = format!("{} {}", my_struct.name, last_name)
}
}
答案 1 :(得分:1)
首先,像"Foo"
这样的文字不是String
,而是&'static str
。区别在于,String
是包含字符串内容的实际分配缓冲区,&str
只是现有缓冲区的视图。因此,&'static str
是对某些静态分配数据的视图。您无法将&str
作为String
传递,因此您的示例应如下所示:
struct MyStruct {
name:String
}
impl MyStruct {
fn foo(&mut self) {
self.name = "Bob".to_string();
self.bar(self, "Foo");
}
fn bar(&mut self, my_struct: MyStruct, last_name: &str) {
self.name = format!("{} {}", my_struct.name, last_name)
}
}
然而,正如您已经注意到的那样,这并不起作用,即使在String -> &str
更改后也无法胜出:
self.bar(self, "Foo")
这也不会:
self.bar(*self, "Foo")
也不是:
let f = *self; // this is not a "raw pointer", BTW, this is just a dereference
self.bar(f, "Foo")
第一个版本仅仅因为类型不匹配而无法工作:self
是&mut MyStruct
,bar()
期望普通MyStruct
作为第一个参数。
如果MyStruct
是Copy
类型(如果它实现了Copy
特征),那么第二个和第三个变体基本上是等效的,可以实际上有用。但是,它并不是因为它包含String
,因为它有一个关联的析构函数,所以它不是Copy
类型。因此,编译器不会为Copy
实现MyStruct
,并且这些类型的值只能移动而不能复制。
但是您无法从&mut
引用中移出某个值,因为引用是非拥有数据视图,因此*self
刚赢了&#39 ; t编译。
此外,还有一个障碍。因为你想以某种方式将self
传递给bar()
,所以你不能使用引用,否则这将是最好的选择。也就是说,这不会起作用:
fn bar(&mut self, my_struct: &MyStruct, last_name: &str) {
self.name = format!("{} {}", my_struct.name, last_name);
}
self.bar(self, "Foo"); // self as an argument is auto-reborrowed from &mut to &
这是因为Rust不允许&mut
同时引用某些数据以及对同一数据的任何其他引用,这正是这里会发生的事情:self.bar(self, "Foo")
方法调用需要&mut MyStruct
作为其目标,但&MyStruct
作为其参数,并且因为self
作为它们两者传递,编译器将拒绝它。
因此,如果您希望代码尽可能接近原始意图,那么最好的选择是使用Clone
。为您的结构导出Clone
:
#[deriving(Clone)]
struct MyStruct {
name: String
}
然后您可以使用clone()
方法获取结构的副本:
impl MyStruct {
fn foo(&mut self) {
self.name = "Bob".to_string();
let c = self.clone();
self.bar(c, "Foo");
}
fn bar(&mut self, my_struct: MyStruct, last_name: &str) {
self.name = format!("{} {}", my_struct.name, last_name)
}
}
但是,您的代码可能需要重组。通常可以更清楚地表达此类内容,例如,将bar()
调用移至foo()
来电。
我强烈建议您阅读the official Rust guide,其中解释了所有权,借阅和参考等概念。之后,您的代码无效的原因应该更加明确。