// 在manager字段中对于第一个'a它是协变的, 对于第二个'a, 由于mut的原因, Manager<'a>是不变的, 所以'a是不变的,因此整体是不变的
struct Interface<'a> {
manager: &'a mut Manager<'a>,
}
impl<'a> Interface<'a> {
pub fn noop(self) {
println!("interface consumed");
}
}
// 在text字段中'a是协变的, 因此Manager对于'a是协变的
struct Manager<'a> {
text: &'a str,
}
// 同理对于List来说, 在'a上是协变的
struct List<'a> {
manager: Manager<'a>,
}
impl<'a> List<'a> {
// 这个方法由于Interface对其生命周期参数是不变的, 导致'a是不变的, 又由于'a与List绑定, 导致对List的&mut(可变借用)会与List本身一致
pub fn get_interface(&'a mut self) -> Interface<'a> {
Interface {
manager: &mut self.manager,
}
}
}
fn main() {
let mut list = List {
manager: Manager { text: "hello" },
};
// 按道理来说这里返回的匿名Interface应该会在这一行后直接被drop掉, 因此list也应该被drop掉(见get_interface注释)
// 但是实际上下面的use_list(&list)的报错是list被可变借用了, 不能再被借用
// 因此我是否可以认为这个那个逆名的Interface没有被dro掉, 它保持到了use_list(&list)的结束
list.get_interface().noop();
println!("Interface should be dropped here and the borrow released");
use_list(&list);
}
fn use_list(list: &List) {
println!("{}", list.manager.text);
}
这个理解是否正确, 请佬教一下我
1
共 12 条评论, 1 页
评论区
写评论好的, 感谢佬的解答,我已经大概可以理解了。
--
👇
xiaoyaou: 时间有点久了,理解也不一定对:
query_with调用要求的是新生命周期'q,参数sql: &'q str,sql是在execute1临时创建的&sql,所以具有&'q sql类型,然后execute1里的sql解构后被async块捕获,相当于&'q sql是引用了异步块的字段,同时,异步块还捕获了arg变量(为异步块引入了'a生命周期),所以就需要要求'q: 'a。这也是我后面想要使用
unsafe { std::mem::transmute::<&str, &'a str>(&sql) }的原因,因为看起来编译器应该是要能推导出'q和'a可以等价才对,但是实际是没法自动推导--
👇
zhangzhenxiang666: 佬我看了你给的链接, 其中有一部分
写 sql: String 是不行的,因为 &sql 在 execute1 函数内创建,需要一种方式表达 DB::Arguments<'a> 中的 'a 与 &'q sql 中的 'q 具有 'q: 'a 关系。这无法被 Rust 的 trait bound 表达这个为什么'q要有'q: 'a的关系呀, 如果实际传入的是DB::Arguments<'a>不是应该要求'a: 'q吗,是因为函数参数里的生命周期是逆变的吗--
👇
xiaoyaou: 看到这个想起来之前也有个类似的讨论:sqlx生命周期问题
时间有点久了,理解也不一定对:
query_with调用要求的是新生命周期'q,参数sql: &'q str,sql是在execute1临时创建的&sql,所以具有&'q sql类型,然后execute1里的sql解构后被async块捕获,相当于&'q sql是引用了异步块的字段,同时,异步块还捕获了arg变量(为异步块引入了'a生命周期),所以就需要要求'q: 'a。这也是我后面想要使用
unsafe { std::mem::transmute::<&str, &'a str>(&sql) }的原因,因为看起来编译器应该是要能推导出'q和'a可以等价才对,但是实际是没法自动推导--
👇
zhangzhenxiang666: 佬我看了你给的链接, 其中有一部分
写 sql: String 是不行的,因为 &sql 在 execute1 函数内创建,需要一种方式表达 DB::Arguments<'a> 中的 'a 与 &'q sql 中的 'q 具有 'q: 'a 关系。这无法被 Rust 的 trait bound 表达这个为什么'q要有'q: 'a的关系呀, 如果实际传入的是DB::Arguments<'a>不是应该要求'a: 'q吗,是因为函数参数里的生命周期是逆变的吗--
👇
xiaoyaou: 看到这个想起来之前也有个类似的讨论:sqlx生命周期问题
u r right
我看的rust教程不是这样的, Rust 秘典(死灵书)
--
👇
wukong: > // 在manager字段中对于第一个'a它是协变的, 对于第二个'a, 由于mut的原因, Manager<'a>是不变的, 所以'a是不变的,因此整体是不变的
应该是第一个
'a就是不变的。&'a mut Manager中的'a就已经是不变的了应该是第一个
'a就是不变的。&'a mut Manager中的'a就已经是不变的了佬我看了你给的链接, 其中有一部分
写 sql: String 是不行的,因为 &sql 在 execute1 函数内创建,需要一种方式表达 DB::Arguments<'a> 中的 'a 与 &'q sql 中的 'q 具有 'q: 'a 关系。这无法被 Rust 的 trait bound 表达这个为什么'q要有'q: 'a的关系呀, 如果实际传入的是DB::Arguments<'a>不是应该要求'a: 'q吗,是因为函数参数里的生命周期是逆变的吗--
👇
xiaoyaou: 看到这个想起来之前也有个类似的讨论:sqlx生命周期问题
看到这个想起来之前也有个类似的讨论:sqlx生命周期问题
感谢
--
👇
zylthinking: 借用检查是编译期分析, 它看到的是源代码, 不会关心运行; 你告诉它 'a 它就在代码里面圈定 'a 的范围; 然后检查这个范围内有没有违反借用规则的语句.
大概就这么理解就行
借用检查是编译期分析, 它看到的是源代码, 不会关心运行; 你告诉它 'a 它就在代码里面圈定 'a 的范围; 然后检查这个范围内有没有违反借用规则的语句.
大概就这么理解就行
确实是一样的效果,那就是&'a mut self已经表明了这个可变引用的生命周期与List<'a>一致, 即使是get_interface(&'a mut self)->()调用完成后可以释放掉了, rust的借用检查器也不会释放掉可变引用对吗
--
👇
zylthinking: ``` pub fn get_interface(&'a mut self) -> Interface<'a>
pub fn get_interface(&'a mut self) -> ()
这里其实和返回的 Interface<'a> 没啥关系 &'a mut self 已经表明了存在一个对 List<'a> 的引用, 它的生命周期持续到 'a 结束; 而 List<'a> 也不可能超过 'a 而存在; 因此, 这基本表明了 &'a mut self 创建出来后, 就别想着直接访问 List<'a> 了
你可以试试这个
估计一样的效果, 如果我理解没有错误的话
有佬告诉我说, 这个形变不会影响那个匿名Interface何时被drop, 那么是不是即使被drop掉了, 在借用检查器中, 可变借用依然存在, 所以编辑器才会报可变借用和借用同时存在的问题