- 主题:rust新手问一下
for val in &vals这句中,val是vals中某个元素的引用,
这个引用如果被直接send到channel的另一侧,那就要求这个引用的生命周期能罩住channel另一侧的使用代码,不然可能出现野指针。
如果send(val.clone()),那么send过去的是复制出来的一个String对象,没有生命周期问题。
【 在 txgx 的大作中提到: 】
: 用11楼的方法,导致12楼的问题, 应该怎么解决?
: @z16166 @ilovecpp
: 15楼的方式的确能解决问题,但是为嘛用引用会有生命周期问题?
: ...................
--
FROM 123.115.133.*
肯定不是这样判断的!rustc还没到这么智能。
它好像是跟线程周期比较,因为线程可认为是'static的,而&val则不是。
不过我觉得send结束对val的引用也应结束,应该是编译器弱智原因。
如果一定要send(&val)的话不知道怎么改。
【 在 txgx 的大作中提到: 】
: use tokio::task::yield_now;
: use std::rc::Rc;
:
: #\[tokio::main\]
: async fn main() {
: tokio::spawn(async {
: let rc = Rc::new("he
: ..................
发自「今日水木 on MRX-W29」
--
FROM 115.52.185.*
你的质疑是对的,rustc不知道(或者说borrow checker不会推导那么厉害)什么数据会传递到另一侧,也没法推导出另一侧的使用周期。
我上面的描述属于想当然了,纯属误导。花点时间搞清这个问题。
【 在 txgx 的大作中提到: 】
: 肯定不是这样判断的!rustc还没到这么智能。
: 它好像是跟线程周期比较,因为线程可认为是'static的,而&val则不是。
: 不过我觉得send结束对val的引用也应结束,应该是编译器弱智原因。
: ...................
--
FROM 123.115.133.*
给send()传递ref是不行的,因为这个ref是在发送线程(或者说负责发送的闭包)里的,
一旦发送线程结束(或者说发送的闭包销毁了),ref即失效,此后接收线程收到这个ref后就是dangling reference。
这样去掉for带来的问题后,也是报错:
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
let v1 = &vals[0];
tx.send(v1).unwrap();
});
或者说,要给send()传递ref,那么这个ref必须是static生命周期的,要求太高。
比如改成这样,表面上看起来ref的生命周期比tx的长。也报错,提示要传递static级别的ref。
fn main() {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
let v1 = &vals[0];
{
//let (tx, rx) = mpsc::channel();
let (tx, rx) = mpsc::channel::<&String>();
thread::spawn(move || {
tx.send(v1).unwrap();
});
for received in rx {
println!("Got: {}", received);
}
}
}
参考的这个:
https://stackoverflow.com/questions/65641458/borrowed-value-does-not-live-long-enough-with-arc-thread-and-channel
https://users.rust-lang.org/t/solved-channel-in-a-loop-in-a-thread-borrowed-value-does-not-live-long-enough/26733
上面第一个链接里总结了lifetime check不跨线程,是thread local的。
第二个链接里有个总结是:不要跨线程传递ref,而是传递owned value。
【 在 txgx 的大作中提到: 】
: 肯定不是这样判断的!rustc还没到这么智能。
: 它好像是跟线程周期比较,因为线程可认为是'static的,而&val则不是。
: 不过我觉得send结束对val的引用也应结束,应该是编译器弱智原因。
: ...................
--
修改:z16166 FROM 123.115.133.*
FROM 123.115.133.*
你的第一个链接里提到了解决办法,给thread 加一个生命期。
https://docs.rs/crossbeam/0.8.0/crossbeam/thread/index.html
【 在 z16166 的大作中提到: 】
: 给send()传递ref是不行的,因为这个ref是在发送线程(或者说负责发送的闭包)里的,
: 一旦发送线程结束(或者说发送的闭包销毁了),ref即失效,此后接收线程收到这个ref后就是dangling reference。
:
: 这样去掉for带来的问题后,也是报错:
: thr
: ..................
发自「今日水木 on MRX-W29」
--
FROM 115.52.185.*
嗯,crossbeam这个例子正好解决了问题。
而且要跨线程传栈变量的引用基本只能用这种范式了,不知道这东西的会卡在这里好久。
不过下一个问题来了:
crossbeam的这个东西怎么向编译器证明传递栈变量的引用是没问题的?
值得dig一下黑魔法。
看这个讨论,是采用了unsafe code来改变生命周期,不过还是不够具体
https://github.com/crossbeam-rs/crossbeam/issues/385
【 在 txgx 的大作中提到: 】
: 你的第一个链接里提到了解决办法,给thread 加一个生命期。
:
https://docs.rs/crossbeam/0.8.0/crossbeam/thread/index.html:
: ...................
--
FROM 123.115.133.*
你引用的链接已经告诉你了:
let closure: Box<FnMut() + Send + 'env> = Box::new(closure);
let closure: Box<FnMut() + Send + 'static> = unsafe { mem::transmute(closure) };
mem::transmute相当于C++的reinterpret_cast,强制类型转换。你把'env的lifetime强制转成'static,自然可以传给任何人。不过你要自己保证实际使用closure的时间不能超过'env。
你不需要向编译器证明unsafe代码的正确性。unsafe其实是把编译器证不过去的步骤,直接写成一个公理。
跟做证明题的时候,证不过去的地方写“显然”差不多。有些人写“显然”是真的想得很清楚。有些人则是证明一卡住就“显然”过去。像后面这样写rust的人好像也不少。
【 在 z16166 的大作中提到: 】
: 嗯,crossbeam这个例子正好解决了问题。
: 而且要跨线程传栈变量的引用基本只能用这种范式了,不知道这东西的会卡在这里好久。
: 不过下一个问题来了:
: ...................
--
修改:ilovecpp FROM 58.37.58.*
FROM 58.37.58.*
一般函数使用参数的规则是函数结束参数就可以释放了。
rust推导生命期为什么不考虑一下呢?
每个函数都加上个引用参数的生命期指示不是方便一点?
比如
'fn 函数生命期
'static app 生命期。
fn bar<'a('a ='fn),T> (v: &'a T)
{}
当成隐含规则
fn bar<'a('a ='static),T> (v: &'a T)
{}
当成特殊情况。
应该给他们提个建议。
哈哈。
当然这样子写的话人们又该乱用指针了,
那就把2当成缺省情况!
【 在 z16166 的大作中提到: 】
: 好,谢谢。用unsafe cast给掰顺了
:
: --
发自「今日水木 on MRX-W29」
--
修改:txgx FROM 115.52.185.*
FROM 115.52.185.*
函数签名上的生命周期符号是解决返回引用的生命周期标注的,没有返回值根本没必要标注生命周期符号
【 在 txgx (纸上谈医) 的大作中提到: 】
: 一般函数使用参数的规则是函数结束参数就可以释放了。
: rust推导生命期为什么不考虑一下呢?
:
: 每个函数都加上个引用参数的生命期指示不是方便一点?
--
FROM 49.90.187.*