我之前搜索过这个问题,比如this和this,但是按照第一个链接的解决方案并尝试将它们应用到我的代码中,rustc 似乎误解了我想要做的事情。
我想创建一个链表并为节点中间分配一些引用并打印它们的值。首先,我使它们可变,以便创建从 head ref 到 tail ref 的列表,然后我想将它们转换为不可变的,从 tail ref 到 head ref,这不会违反所有权规则。最后,我想访问一些不可变的引用(中点)来获取它们的值。
我的代码:(游乐场)
struct Node<T> {
val: T,
next: Option<Box<Node<T>>>,
}
impl<T> Node<T> {
fn new(val: T) -> Option<Box<Node<T>>> {
Some(Box::new(Node { val, next: None }))
}
}
fn main() {
let head = &mut Node::new(0);
let a = &mut head.as_mut().unwrap().next;
*a = Node::new(10);
let b = &mut a.as_mut().unwrap().next;
*b = Node::new(20);
let c = &mut b.as_mut().unwrap().next;
*c = Node::new(30);
let tail …Run Code Online (Sandbox Code Playgroud) 我注意到 Option<&T> 和 Option<T> 的映射函数有些奇怪,经过快速谷歌搜索后,还有其他人注意到了同样的问题,如 这个问题中所述。我将仅使用相同的示例。
let greet: Option<String> = Some("hi".to_string());
let mapped = greet.map(|e|e);
dbg!(mapped);
dbg!(greet);
Run Code Online (Sandbox Code Playgroud)
错误消息是:
use of moved value: `greet` ....
Run Code Online (Sandbox Code Playgroud)
另一方面,下面的代码是可以的。
let greet: Option<String> = Some("hi".to_string());
let mapped = greet.as_ref().map(|e|e);
dbg!(mapped);
dbg!(greet);
Run Code Online (Sandbox Code Playgroud)
地图函数的类型是:
pub const fn map<U, F>(self, f: F) -> Option<U>
Run Code Online (Sandbox Code Playgroud)
因此,调用者的所有权应该转移到映射中的“self”,该问题的解释是“Option<&T>implements Copy”。
因此,Option<T> 转移所有权从而导致错误,而 Option<&T> 只是创建一个新副本。
但是,我找不到任何显示“Option<&T> Implements Copy”的地方,更糟糕的是,来自文档:
/// The `Option` type. See [the module level documentation](self) for more.
#[derive(Copy, PartialOrd, Eq, Ord, Debug, Hash)]
#[rustc_diagnostic_item = "Option"] …Run Code Online (Sandbox Code Playgroud) 我正在努力寻找一种优雅的解决方案来访问 Rust 中的嵌套地图以实现只读目的。我有这种情况,理想情况下,作为示例,我可以返回对空映射的引用(这当然不起作用,因为空哈希映射由函数拥有):
struct S {
stuff: HashMap<A, HashMap<B, C>>
}
impl S {
fn get(&self, a: &A) -> &HashMap<B,C> {
return self.stuff.get(a).unwrap_or(&HashMap::new());
}
}
Run Code Online (Sandbox Code Playgroud)
无法保证地图内容将具有键 a,因此必须处理可选性。
我希望解决方案以有效的方式(无副本/移动)实现使用此或类似签名的方法 get ,因为地图内容可能非常大。
我只能想到以下解决方案,但我认为一定有更直接的解决方案:
在我看来,解决方案(3)是实现上述目标的最佳方法,但也许我遗漏了一些东西,并且有更直接的方法?
我们都知道返回对局部变量的引用是个坏主意.但是,我想知道返回引用是否真的是一个好主意,如果有可能确定何时或何时不执行它的一些好规则.
返回引用的问题在于调用函数需要关心不应该负责的对象的生命周期.作为一个人为的例子:
#include <vector>
const int& foo() {
std::vector<int> v = {1, 2, 3, 4, 5};
return v[0];
}
int main(int argc, const char* argv[])
{
const int& not_valid = foo();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里,vector超出范围foo,破坏其内容并使对其元素的任何引用无效.vector::operator[]返回对元素的引用,因此当进一步返回此引用时foo,引用处于main悬空状态.我不相信const引用会延长这里的生命周期,因为它不是对临时引用的引用.
正如我所说,这是一个人为的例子,作者foo可能不会那么愚蠢地试图v[0]作为参考.但是,很容易看出返回引用如何要求调用者关心它不拥有的对象的生命周期.将元素推送到vector副本中,然后由vector它负责.传递引用参数不存在此问题,因为您知道函数将在调用者继续并销毁对象之前完成.
我可以看到返回一个引用允许一些很好的类似数组的语法v[0] = 5- 但是有一个成员函数是什么样的糟糕v.set(index, value)?至少我们不会暴露内部对象.我知道返回引用可能会有性能提升,但是对于RVO,命名RVO(NRVO)和移动语义,它可以忽略不计或不存在.
所以我一直试图想象在什么情况下返回引用是真正安全的,但我无法理解它可能涉及的所有权语义的所有不同排列.何时这样做有什么好的规则?
注意:我知道更好的方法来处理vectors中的所有权是使用智能指针,但是你会遇到一个不同的对象 - 谁拥有智能指针?
假设我有:
class Metadata {
// stores expensive-to-copy data, provides complex interface to access/modify
}
class SomeObject
public:
Metadata& GetMetadata() { return mMetadata; }
private:
Metadata mMetadata;
}
boost::shared_ptr<SomeObject> obj = ...;
obj->GetMetadata().SetTitle("foo");
obj->GetMetadata().GetTitle();
Run Code Online (Sandbox Code Playgroud)
普遍的共识似乎是,通过引用返回,尤其是非常数,在除了少数特定情况之外的所有情况下都非常糟糕.但是,在这种情况下,它似乎是最好的(也是唯一的?)选项:
它引入了一个模糊的要求,即SomeObject能够通过引用传回元数据,这意味着必须有一个Metadata对象,其生命周期与SomeObject的生命周期相同(或者更长) - 但是,这是对象之间的确切语义关系,并要求肯定比上述任何选项更好.
在我看来,我可以引入某种不可复制的指针类型并返回它,但那闻起来很有趣/似乎有点矫枉过正.我可以让SomeObject拥有一个boost :: shared_ptr,但这真的不是我想到的语义的一个很好的匹配(基本上:如果你现在修改,修改原始 - 如果你以后读/存储,制作副本并自己跟踪).
这里有更好的模式吗?我会以某种方式在脚下射击自己吗?
我正在通过这个 Rust教程,我正在尝试解决这个问题:
实现一个函数,
incrementMut它将整数向量作为输入,并通过将每个值递增1来修改原始列表的值.
这似乎是一个相当简单的问题,是吗?
我一直试图找到一段时间的编译解决方案,但我开始失去希望.这是我到目前为止:
fn main() {
let mut p = vec![1i, 2i, 3i];
increment_mut(p);
for &x in p.iter() {
print!("{} ", x);
}
println!("");
}
fn increment_mut(mut x: Vec<int>) {
for &mut i in x.iter() {
i += 1;
}
}
Run Code Online (Sandbox Code Playgroud)
这是编译器在我尝试编译时所说的内容:
Compiling tut2 v0.0.1 (file:///home/nate/git/rust/tut2)
/home/nate/git/rust/tut2/src/main.rs:5:12: 5:13 error: use of moved value: `p`
/home/nate/git/rust/tut2/src/main.rs:5 for &x in p.iter() {
^
/home/nate/git/rust/tut2/src/main.rs:3:16: 3:17 note: `p` moved here because it has type `collections::vec::Vec<int>`, which is non-copyable …Run Code Online (Sandbox Code Playgroud) 我正在努力弄清所有权和借贷检查器。我遇到了一个设法解决的问题,但我认为应该有一种更符合人体工程学的方法来解决。
下面的代码跳闸借检查,因为我试图移动file.filepath到thisfile_path,而它在借来的上下文。
for file in &self.filelist {
let thisfile_path = String::from(file.filepath);
let this_wd = self.notifier.add_watch(Path::new(&file.filepath), watch_mask::CLOSE_WRITE).unwrap();
let this_watch = Watchlist {configfile: thisfile_path, watchd: this_wd};
watches.push(this_watch);
}
Run Code Online (Sandbox Code Playgroud)
&self.filelist是Vec<ConfigFiles>ConfigFiles是的位置struct。
我正在遍历filelist,我想将一个字段从ConfigFiles结构复制到一个新的Vec。
如果我替换为该行将
let thisfile_path = String::from(&file.filepath);
不起作用,因为未实现trait转换&String。
我找到了一种解决方法,但我认为这不是理想的解决方法:
let thisfile_path = String::from(&file.filepath[..]);
Run Code Online (Sandbox Code Playgroud)
这是我解决这个问题的唯一方法吗?
我正在努力了解所有权模式.由于Rust中只能有一个所有者,这是否意味着浅拷贝是不可能的?有没有类似于浅拷贝的东西?我猜你可以用引用做一些事情,但这会迫使你使用不同的类型?
我试图将变量的所有权赋予循环中的函数,并且我有自己的布尔值以确保它只发生一次,但是编译器告诉我在前一次迭代中移动了值.
这是一个例子:
fn take_ownership(a: String) {
println!("{}", a);
}
fn main() {
let mut a = true;
let hello = "Hello".to_string();
for _ in 0..5 {
if a {
a = false;
take_ownership(hello);
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用此代码,编译器告诉我:
error[E0382]: use of moved value: `hello`
--> src/main.rs:12:28
|
12 | take_ownership(hello);
| ^^^^^ value moved here in previous iteration of loop
Run Code Online (Sandbox Code Playgroud)
有没有办法告诉编译器"没关系,我会处理它"?我不想使用references(&).
我是Rust的新手。我需要在for循环之前创建一个向量。运行循环。在for循环内更改向量。然后在for循环之后更改向量。
我尝试了以下代码,并尝试使用不可变借位,但两者均无效。
fn main() {
let mut vec1 = vec![4, 5];
vec1.push(6);
for i in vec1 {
if i % 2 == 0 {
vec1.push(7);
}
}
vec1.push(8);
println!("vec1={:?}", vec1);
}
Run Code Online (Sandbox Code Playgroud)
我希望在for循环内和之后编译和更改向量。但它显示此错误消息:
fn main() {
let mut vec1 = vec![4, 5];
vec1.push(6);
for i in vec1 {
if i % 2 == 0 {
vec1.push(7);
}
}
vec1.push(8);
println!("vec1={:?}", vec1);
}
Run Code Online (Sandbox Code Playgroud)
您能解释为什么会发生移动吗?你可以编译吗?