函数返回一个闭包,该闭包返回一个使用环境变量的闭包

时间:2018-10-01 03:33:47

标签: rust

functionA返回closureA,而closureA返回closureBclosureB,它们使用来自functionA周围环境的变量。

fn main () {
   type Closure1 = Box<Fn() -> ()>;
   type Closure2 = Box<Fn() -> Closure1>;

   fn closure_container() -> Closure2 {
       let mut a: Vec<usize> = Vec::new();
       let closure2: Closure2 = Box::new(move || {
           let closure1 = || {
               println!("{}", a)
           };
           Box::new(closure1)
       });

       closure2
   }
}
error[E0507]: cannot move out of captured outer variable in an `Fn` closure
 --> src/main.rs:9:27
  |
6 |        let mut a: Vec<usize> = Vec::new();
  |            ----- captured outer variable
...
9 |            let closure1 = move || {
  |                           ^^^^^^^ cannot move out of captured outer variable in an `Fn` closure

它将编译let mut a = 100;,但是let mut a: Vec<usize> = Vec::new();将报告错误!我不知道如何解决。

1 个答案:

答案 0 :(得分:1)

您(正确地)将function add_content_after_addtocart() { global $woocommerce; // get the current post/product ID $current_product_id = get_the_ID(); // get the product based on the ID $product = wc_get_product( $current_product_id ); // get the "Checkout Page" URL $checkout_url = WC()->cart->get_checkout_url(); // run only on simple products if( $product->is_type( 'variable' ) ){ ?> <script> jQuery(function($) { <?php /* if our custom button is clicked, append the string "&quantity=", and also the quantitiy number to the URL */ ?> // if our custom button is clicked $(".custom-checkout-btn").on("click", function() { // get the value of the "href" attribute $(this).attr("href", function() { // return the "href" value + the string "&quantity=" + the current selected quantity number return this.href + '&quantity=' + $('input.qty').val(); }); }); }); </script> <?php echo '<div class="col-sm-6"><div class="buy_now"><a href="'.$checkout_url.'?add-to-cart='.$current_product_id.'" class="single_add_to_cart_button buy_now_button button alt disabled custom-checkout-btn ajax_add_to_cart" >Buy Now</a></div></div><div class="clearfix"></div>'; ?> <?php } else if( $product->is_type( 'simple' ) ){ echo '</div><div class="col-sm-6"><div class="p-t-35"></div><div class="buy_now"><a href="'.$checkout_url.'?add-to-cart='.$current_product_id.'" class="single_add_to_cart_button button alt buy_now_button button alt">Buy Now</a></div></div><div class="clearfix"></div>'; } } add_action( 'woocommerce_after_add_to_cart_button', 'add_content_after_addtocart' ); 用于第一个闭包(第7行),但还需要将其添加到第二个闭包(第8行):

move

playground

如果 let closure2: Closure2 = Box::new(move || { let closure1 = move || { // <-- Add "move" on this line println!("{}", a) }; Box::new(closure1) }); 具有a类型,则可以工作,但是当Copy不是cannot move out of captured outer variable in an 'Fn' closure时(例如,如果{{ 1}}是a)。问题是由于您将Copy定义为a的事实,这意味着您正在告诉编译器您可能想多次调用它。但是,第一次调用Vec会将closure2移到返回的Fn中,因此closure2将不可用于下一次对a的调用。

长话短说:您需要将closure1定义为a,以告诉编译器您不能多次调用它,或者您需要移动closure2的副本放入closure2中,以便FnOnce保留其副本。

解决方案1:a

closure1

playground

但是请注意,尽管您可以通过这种方式创建 closure2,但是在当前稳定的Rust中无法调用。如果您愿意每晚使用,则将FnOnce替换为FnBox应该可以,但是我遇到了另一个错误(playground)。目前,您将需要使用解决方案2并克隆type Closure1 = Box<Fn() -> ()>; type Closure2 = Box<FnOnce() -> Closure1>; fn closure_container() -> Closure2 { let a: Vec<usize> = Vec::new(); let closure2: Closure2 = Box::new(move || { let closure1 = move || { println!("{:?}", a) }; Box::new(closure1) }); closure2 } 。如果要避免克隆整个载体的开销,可以wrap it in an Rc and clone thatplayground)。

解决方案2:克隆

Closure2

playground