#helper #macro #proc-macro #create #function #capture #closure-like

helper_fn

一个用于创建类似闭包的辅助函数的宏

1 个不稳定发布

0.1.0 2021 年 9 月 21 日

#115#capture

MIT 许可证

11KB
217

helper_fn

一个用于创建类似闭包的辅助函数的宏。

用法

此属性可以应用于函数项,允许它从父作用域继承变量。辅助函数必须在使用之前和继承的变量之后声明。

use helper_fn::helper_fn;

let mut num = 5;

#[helper_fn(num: i32)] // captures num from the surrounding scope
fn get_num() -> i32 {
  num
}

assert_eq!(get_num!(), 5); // note that this is a macro invocation, not a function call

变量可以通过值(使用移动或复制语义)、通过引用或通过可变引用进行捕获

#[helper_fn(copied: i32, moved: Vec<i32>, &by_ref: Foo, &mut by_mut_ref: Bar)]

如果存在作用域问题,可以使用 use_helper_fn

use helper_fn::{helper_fn, use_helper_fn};

let mut num = 5;

// hoist the definitions
use_helper_fn! {
  get_num(num),
  get_num_times_two(num) as get_num_times_2,
  increment_num(&mut num),
};

assert_eq!(get_num!(), 5);
assert_eq!(get_num_times_2!(), 10);
increment_num!();
assert_eq!(get_num!(), 6);
assert_eq!(get_num_times_2!(), 12);

#[helper_fn(num: i32)]
fn get_num() -> i32 {
  num
}

#[helper_fn(num: i32)]
fn get_num_times_two() -> i32 {
  // reuse the definition from the parent scope
  // has to be a different name to avoid conflict
  use_helper_fn!(get_num(num) as get_num_);
  get_num_!() * 2
}

#[helper_fn(&mut num: i32)]
fn increment_num() {
  *num += 1;
}

理由

闭包经常用作需要周围作用域的辅助函数;以下是一个简单示例

let mut num = 5;

let get_num = || {
  // Lots of complex stuff
  num
};

assert_eq!(get_num(), 5);

这没问题,但如果在两次调用之间修改了 num,则无法编译

let mut num = 5;

let get_num = || {
  // Lots of complex stuff
  num
};

assert_eq!(get_num(), 5);
num += 1; // cannot assign to `num` because it is borrowed
assert_eq!(get_num(), 6);

一种解决方案是在本地使用 fn 项并传递变量

let mut num = 5;

fn get_num(num: i32) -> i32 {
  // Lots of complex stuff
  num
}

assert_eq!(get_num(num), 5);
num += 1; // this is ok
assert_eq!(get_num(num), 6);

这可以工作,但如果有多个变量,可能会变得相当冗长。

使用 helper_fn,您可以同时获得两者的优点

use helper_fn::helper_fn;

let mut num = 5;

#[helper_fn(num: i32)]
fn get_num() -> i32 {
  num
}

assert_eq!(get_num!(), 5); // you don't need to pass in `num`
num += 1; // this is ok
assert_eq!(get_num!(), 6); // note that these calls are macro invocations

依赖关系

~1.5MB
~35K SLoC