如何在嵌套映射中使用闭包?

时间:2015-06-04 23:12:06

标签: closures rust

我正在尝试从创建每个元素的仿函数创建一个二维矩阵,并将其存储为平面/*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; CREATE DATABASE /*!32312 IF NOT EXISTS*/`a3823833_MiniPost` /*!40100 DEFAULT CHARACTER SET latin1 */; USE `a3823833_MiniPost`; /*Table structure for table `user` */ DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `userid` bigint(10) NOT NULL, `username` varchar(20) NOT NULL, `password` varchar(20) NOT NULL, `email` varchar(50) NOT NULL, PRIMARY KEY (`userid`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; /*Table structure for table `profile` */ DROP TABLE IF EXISTS `profile`; CREATE TABLE `profile` ( `userid` int(11), `lastName` varchar(50), `firstName` varchar(50), `dob` varchar(10), PRIMARY KEY (`userid`), CONSTRAINT `profile_fk` FOREIGN KEY (`userid`) REFERENCES `user` (`userid`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; (每行连接)。

我使用嵌套的Vec(实际上是map和嵌套的flat_map)来创建每一行并将其连接起来。 Here is what I tried

map

不幸的是,我在编译期间遇到错误:

fn make<T, F>(n: usize, m: usize, f: F) -> Vec<T>
where
    F: Fn(usize, usize) -> T,
{
    (0..m).flat_map(|y| (0..n).map(|x| f(x, y))).collect()
}

fn main() {
    let v = make(5, 5, |x, y| x + y);

    println!("{:?}", v);
}

如何在嵌套地图中使用闭包?我解决了这个问题by using a single map on 0..n*m,但我仍然对答案感兴趣。

2 个答案:

答案 0 :(得分:7)

在你的情况下,内部闭包|x| f(x,y)是一个借用闭包,它通过引用获取其环境(yf)。

.flat_map(..)的工作方式,禁止您保留对y的引用,而y不是来自外部范围。因此,我们需要让您的闭包按值获取其环境,usize Copy (0..m).flat_map(|y| (0..n).map(move |x| f(x, y))).collect() error[E0507]: cannot move out of captured outer variable in an `FnMut` closure --> src/main.rs:5:36 | 1 | fn make<T, F>(n: usize, m: usize, f: F) -> Vec<T> | - captured outer variable ... 5 | (0..m).flat_map(|y| (0..n).map(move |x| f(x,y))).collect() | ^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure 不是问题:

f

然而,现在又出现了另一个问题:

m

在这里,我们试图将1移动到闭包中,这绝对不可能(除非fFn(usize, usize) -> T,但编译器无法知道)。

由于&&,我们也可以明确传递Copy引用,而fn make<T, F>(n: usize, m: usize, f: F) -> Vec<T> where F: Fn(usize, usize) -> T, { let f_ref = &f; (0..m) .flat_map(|y| (0..n).map(move |x| f_ref(x, y))) .collect() } 引用为y

f_ref

在这种情况下,闭包按值获取其环境,此环境由Copyifelse(x < 100, sprintf("%0.2f", x), sprintf("%0.5e", x)) # [,1] [,2] [,3] [,4] [,5] #[1,] "9.99999e+06" "-0.79" "-0.56" "0.91" "-2.57" #[2,] "-0.13" "9.99999e+06" "-1.83" "-0.34" "1.73" #[3,] "-0.48" "0.38" "1.00000e+07" "1.40" "-0.32" #[4,] "-0.05" "-0.62" "0.91" "1.00000e+07" "1.15" #[5,] "-0.09" "-0.33" "-0.16" "0.35" "9.99999e+06" 组成,两者都是noquote(ifelse(x < 100, sprintf("%0.2f", x), sprintf("%0.5e", x))) # [,1] [,2] [,3] [,4] [,5] #[1,] 9.99999e+06 -0.79 -0.56 0.91 -2.57 #[2,] -0.13 9.99999e+06 -1.83 -0.34 1.73 #[3,] -0.48 0.38 1.00000e+07 1.40 -0.32 #[4,] -0.05 -0.62 0.91 1.00000e+07 1.15 #[5,] -0.09 -0.33 -0.16 0.35 9.99999e+06 ,一切都很顺利。

答案 1 :(得分:1)

添加到Levans's excellent answer中的另一种定义函数的方法是

fn make<T, F>(n: usize, m: usize, f: F) -> Vec<T>
where
    F: Fn(usize, usize) -> T + Copy,
{
    (0..m).flat_map(|y| (0..n).map(move |x| f(x, y))).collect()
}

由于我们知道|x, y| x + yCopy类型,因此f将为flat_map调用的每个回调复制。我仍然希望使用Levans的方法,因为它不如复制参考文献有效。