2014-01-15 12 views
3

注意,這個問題涉及返回一個封閉的版本鏽1.0發佈從功能

我是否正確,現在是不可能從一個函數返回一個閉包,除非它理解前提供給函數的參數?這是非常有用的方法,例如,當我需要在程序的不同部分中使用相同的代碼塊時,參數化方式不同。目前,編譯器不允許這樣的事情,自然:

fn make_adder(i: int) -> |int| -> int { 
    |j| i + j 
} 

的封閉被分配在堆棧上,並在從函數返回被釋放,所以不可能歸還。

將來有可能做這項工作嗎?我聽說動態大小的類型會允許這樣做。

+0

好吧有盒裝關閉語法... https://github.com/alco/blog/blob/master/posts/2013-07-22-Rust-lambdas.md#boxed-closures但現在我不知道如何使相同。似乎只有在答案解決方案中提供是唯一的方法。 – Cynede

+0

@ Heather,是的,這些類型的封閉在0.9之前被刪除了一段時間。 –

回答

3

這不能用於堆棧封閉;它需要既沒有環境也沒有自己的環境。 DST提案確實包括重新引入具有所有權環境的封閉類型(~Fn)的可能性,這將滿足您的需求,但尚不清楚這是否會發生。

實際上,還有其他方法可以做到這一點。例如,你可以這樣做:

pub struct Adder { 
    n: int, 
} 

impl Add<int, int> for Adder { 
    #[inline] 
    fn add(&self, rhs: &int) -> int { 
     self.n + *rhs 
    } 
} 

fn make_adder(i: int) -> Adder { 
    Adder { 
     n: int, 
    } 
} 

然後,而不是make_adder(3)(4) == 7,這將是make_adder(3) + 4 == 7,或make_adder(3).add(&4) == 7。 (這是Add<int, int>,它正在實施,而不僅僅是一個impl Adder { fn add(&self, other: int) -> int { self.n + other }僅僅是爲了讓你的+操作的便利性。)

這是一個相當愚蠢的例子,作爲Adder或許也同樣適用於所有的int可能性,但它有其可能性。

讓我們說你想要返回一個計數器;您可能希望將它作爲返回(0, func)的函數,後一個元素是將返回(1, func),& c的函數。但是,這可能是與迭代器更好的建模:

use std::num::{Zero, One}; 

struct Counter<T> { 
    value: T, 
} 

impl<T: Add<T, T> + Zero + One + Clone> Counter<T> { 
    fn new() -> Counter<T> { 
     Counter { value: Zero::zero() } 
    } 
} 

impl<T: Add<T, T> + Zero + One + Clone> Iterator<T> for Counter<T> { 
    #[inline] 
    fn next(&mut self) -> Option<T> { 
     let mut value = self.value.clone(); 
     self.value += One::one(); 
     Some(value) 
    } 

    // Optional, just for a modicum of efficiency in some places 
    #[inline] 
    fn size_hint(&self) -> (uint, Option<uint>) { 
     (uint::max_value, None) 
    } 
} 

同樣,你看到具有對象的在你調用一個方法變異的狀態,並返回所需的值,而不是創建一個新的概念調用。就是這樣:目前,您可能想撥打object(),您需要致電object.method()。我相信你可以忍受目前存在的那種小小的不便。

+0

謝謝你的詳細解釋。是的,結構是現在這樣做的方式(好吧,閉包是窮人的對象,反之亦然,不是嗎?:)),但返回閉包的優點是非常簡潔的語法,沒有語義和句法額外開銷結構和impls。希望自己的關閉將返回給我們一些日子:) –

+0

如果我想要一個函數返回一些我可以傳遞給'map'的函數呢?我無法每次都認真定義一個新的迭代器類型作爲解決方法。 –

+0

@SebastianRedl:對不起,但現在新的迭代器類型是唯一的方法來做到這一點。 –