< 返回版块

wuqingyi 发表于 2024-04-29 15:15

fn main() {
    let expensive_closure = |x| { x };
    println!("{}", *expensive_closure(&1));
    let expensive_closure2 = |x: i32| { x };
    println!("{}", expensive_closure2(1));
    // 下面这个报错了
    let expensive_closure3 = |x: &i32| { x };
    println!("{}", *expensive_closure2(&1));
}

报错信息:

error: lifetime may not live long enough
 --> src/bin/closure_lifetime.rs:6:42
  |
6 |     let expensive_closure2 = |x: &i32| { x };
  |                                  -   -   ^ returning this value requires that `'1` must outlive `'2`
  |                                  |   |
  |                                  |   return type of closure is &'2 i32
  |                                  let's call the lifetime of this reference `'1`

评论区

写评论
作者 wuqingyi 2024-04-30 12:30

感谢大家的回复,closure_lifetime_binder 应该是我想要的,或者就不加类型标注。

👇
TinusgragLin: 不加类型标注就可以了:

let expensive_closure3 = |x| x;

不过这样 x 的类型似乎被推断成了 &'closure i32(我有找到似乎与此有关的一个 issue),于是下面的代码就报错了:

let mut x = 42;
let expensive_closure3 = |x| x;
expensive_closure3(&x);
&mut x;
let _ = expensive_closure3;
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
  --> src/main.rs:19:5
   |
18 |     expensive_closure3(&x);
   |                        -- immutable borrow occurs here
19 |     &mut x;
   |     ^^^^^^ mutable borrow occurs here
20 |     let _ = expensive_closure3;
   |             ------------------ immutable borrow later used here

经过 google,好像可以通过这种类型提示帮助函数来解决:

fn _hint<F: for<'a> Fn(&'a i32) -> &'a i32>(f: F) -> F { f }
// or
fn __hint<F: Fn(&i32) -> &i32>(f: F) -> F { f }
let mut x = 42;
let expensive_closure3 = _hint(|x| x);
expensive_closure3(&x);
x += 42;
let _ = expensive_closure3;

或者用还没稳定的 closure_lifetime_binder

let mut x = 42;
let expensive_closure3 = for<'a> |x: &'a i32| -> &'a i32 { x };
expensive_closure3(&x);
x += 42;
let _ = expensive_closure3;

当然如果没有捕获外部环境的需求的话,我感觉还是用函数靠谱。

TinusgragLin 2024-04-29 17:28

我发现有许多像 closure_lifetime_binder 这样明明没有标注 unresolved questions 但就是没有推到 stable 的 feature,眼馋呐!

TinusgragLin 2024-04-29 17:24

好像不用显式地用 for<'a> ... 标注,T: Fn(&i32) -> &i32 就可以了,lifetime elision 规则帮大忙。

--
👇
bestgopher: ``` fn main() { let expensive_closure = |x| x; println!("{}", *expensive_closure(&1)); let expensive_closure2 = |x: i32| x; println!("{}", expensive_closure2(1)); // 下面这个报错了 let expensive_closure3 = wapper(|x: &i32| x); println!("{}", *expensive_closure3(&1)); }

fn wapper(f: T) -> T where T: for<'a> Fn(&'a i32) -> &'a i32 { f }

变通下,这样不会转成fn?

bestgopher 2024-04-29 17:14
fn main() {
    let expensive_closure = |x| x;
    println!("{}", *expensive_closure(&1));
    let expensive_closure2 = |x: i32| x;
    println!("{}", expensive_closure2(1));
    // 下面这个报错了
    let expensive_closure3 = wapper(|x: &i32| x);
    println!("{}", *expensive_closure3(&1));
}

fn wapper<T>(f: T) -> T
where T: for<'a> Fn(&'a i32) -> &'a i32 {
    f
}

变通下,这样不会转成fn?

TinusgragLin 2024-04-29 16:58

不加类型标注就可以了:

let expensive_closure3 = |x| x;

不过这样 x 的类型似乎被推断成了 &'closure i32(我有找到似乎与此有关的一个 issue),于是下面的代码就报错了:

let mut x = 42;
let expensive_closure3 = |x| x;
expensive_closure3(&x);
&mut x;
let _ = expensive_closure3;
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
  --> src/main.rs:19:5
   |
18 |     expensive_closure3(&x);
   |                        -- immutable borrow occurs here
19 |     &mut x;
   |     ^^^^^^ mutable borrow occurs here
20 |     let _ = expensive_closure3;
   |             ------------------ immutable borrow later used here

经过 google,好像可以通过这种类型提示帮助函数来解决:

fn _hint<F: for<'a> Fn(&'a i32) -> &'a i32>(f: F) -> F { f }
// or
fn __hint<F: Fn(&i32) -> &i32>(f: F) -> F { f }
let mut x = 42;
let expensive_closure3 = _hint(|x| x);
expensive_closure3(&x);
x += 42;
let _ = expensive_closure3;

或者用还没稳定的 closure_lifetime_binder

let mut x = 42;
let expensive_closure3 = for<'a> |x: &'a i32| -> &'a i32 { x };
expensive_closure3(&x);
x += 42;
let _ = expensive_closure3;

当然如果没有捕获外部环境的需求的话,我感觉还是用函数靠谱。

TinusgragLin 2024-04-29 16:58

这确实是在做类型转换

  • Non capturing closures to fn pointers

--
👇
Cherrs: 他代码是让你显式标注下生命周期

👇
wuqingyi: 这是强转成函数是吗?

--
👇
bestgopher:

fn main() {
    let expensive_closure = |x| x;
    println!("{}", *expensive_closure(&1));
    let expensive_closure2 = |x: i32| x;
    println!("{}", expensive_closure2(1));
    // 下面这个报错了
    let expensive_closure3: for<'a> fn(&'a i32) -> &'a i32 = |x: &i32| x;
    println!("{}", *expensive_closure3(&1));
}

Cherrs 2024-04-29 16:37

他代码是让你显式标注下生命周期

👇
wuqingyi: 这是强转成函数是吗?

--
👇
bestgopher:

fn main() {
    let expensive_closure = |x| x;
    println!("{}", *expensive_closure(&1));
    let expensive_closure2 = |x: i32| x;
    println!("{}", expensive_closure2(1));
    // 下面这个报错了
    let expensive_closure3: for<'a> fn(&'a i32) -> &'a i32 = |x: &i32| x;
    println!("{}", *expensive_closure3(&1));
}

作者 wuqingyi 2024-04-29 16:14

这是强转成函数是吗?

--
👇
bestgopher:

fn main() {
    let expensive_closure = |x| x;
    println!("{}", *expensive_closure(&1));
    let expensive_closure2 = |x: i32| x;
    println!("{}", expensive_closure2(1));
    // 下面这个报错了
    let expensive_closure3: for<'a> fn(&'a i32) -> &'a i32 = |x: &i32| x;
    println!("{}", *expensive_closure3(&1));
}

bestgopher 2024-04-29 15:39
fn main() {
    let expensive_closure = |x| x;
    println!("{}", *expensive_closure(&1));
    let expensive_closure2 = |x: i32| x;
    println!("{}", expensive_closure2(1));
    // 下面这个报错了
    let expensive_closure3: for<'a> fn(&'a i32) -> &'a i32 = |x: &i32| x;
    println!("{}", *expensive_closure3(&1));
}

1 共 9 条评论, 1 页