gpt4 book ai didi

rust - 借用循环内使用的可变成员

转载 作者:行者123 更新时间:2023-11-29 08:28:24 25 4
gpt4 key购买 nike

我要解决的问题是:

Given the recursively nested data structure, eg. a JSON tree, and a path pointing to (possibly non-existent) element inside it, return the mutable reference of the element, that's the closest to given path.

示例:如果我们有格式为 { a: { b: { c: "foo"} } } 和路径 a.b.d 的 JSON 文档,我们希望拥有指向存储在键“b”下的值的可变指针。

这是一个代码片段,到目前为止我得到的是:

use std::collections::HashMap;

enum Json {
Number(i64),
Bool(bool),
String(String),
Array(Vec<Json>),
Object(HashMap<String, Json>)
}

struct Pointer<'a, 'b> {
value: &'a mut Json,
path: Vec<&'b str>,
position: usize
}

/// Return a mutable pointer to JSON element having shared
/// the nearest common path with provided JSON.
fn nearest_mut<'a,'b>(obj: &'a mut Json, path: Vec<&'b str>) -> Pointer<'a,'b> {
let mut i = 0;
let mut current = obj;
for &key in path.iter() {
match current {
Json::Array(array) => {
match key.parse::<usize>() {
Ok(index) => {
match array.get_mut(index) {
Some(inner) => current = inner,
None => break,
}
},
_ => break,
}
} ,
Json::Object(map) => {
match map.get_mut(key) {
Some(inner) => current = inner,
None => break
}
},
_ => break,
};
i += 1;
}
Pointer { path, position: i, value: current }
}

问题是这没有通过 Rust 的借用检查器,因为 current 被借用为可变引用两次,一次在 match 语句内,一次在函数末尾,当构造指针时方法。

我尝试了不同的方法,但没有想出如何实现目标(可能走不安全的路)。

最佳答案

我完全误读了你的问题,我欠你一个道歉。

你不能一次完成 - 你需要做一个只读的过程来找到最近的路径(或确切的路径),然后一个读写的过程来实际提取引用,或者通过闭包形式的增变函数。

我已经 implemented两次通过的方法。请注意,它仍然非常高效:

fn nearest_mut<'a, 'b>(obj: &'a mut Json, path: Vec<&'b str>) -> Pointer<'a, 'b> {
let valid_path = nearest_path(obj, path);
exact_mut(obj, valid_path).unwrap()
}
fn exact_mut<'a, 'b>(obj: &'a mut Json, path: Vec<&'b str>) -> Option<Pointer<'a, 'b>> {
let mut i = 0;
let mut target = obj;
for token in path.iter() {
i += 1;
// borrow checker gets confused about `target` being mutably borrowed too many times because of the loop
// this once-per-loop binding makes the scope clearer and circumvents the error
let target_once = target;
let target_opt = match *target_once {
Json::Object(ref mut map) => map.get_mut(*token),
Json::Array(ref mut list) => match token.parse::<usize>() {
Ok(t) => list.get_mut(t),
Err(_) => None,
},
_ => None,
};
if let Some(t) = target_opt {
target = t;
} else {
return None;
}
}
Some(Pointer {
path,
position: i,
value: target,
})
}
/// Return a mutable pointer to JSON element having shared
/// the nearest common path with provided JSON.
fn nearest_path<'a, 'b>(obj: &'a Json, path: Vec<&'b str>) -> Vec<&'b str> {
let mut i = 0;
let mut target = obj;
let mut valid_paths = vec![];
for token in path.iter() {
// borrow checker gets confused about `target` being mutably borrowed too many times because of the loop
// this once-per-loop binding makes the scope clearer and circumvents the error
let target_opt = match *target {
Json::Object(ref map) => map.get(*token),
Json::Array(ref list) => match token.parse::<usize>() {
Ok(t) => list.get(t),
Err(_) => None,
},
_ => None,
};
if let Some(t) = target_opt {
target = t;
valid_paths.push(*token)
} else {
return valid_paths;
}
}
return valid_paths
}

原理很简单——我重用了我在最初问题中写的方法,以获得最近的有效路径(或确切路径)。

从那里,我将其直接输入我在原始答案中的函数,并且由于我确定路径是有效的(来自先前的函数调用)我可以安全地 unwrap() :-)

关于rust - 借用循环内使用的可变成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57852563/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com