先看下Lambda表达式里面修改外部变量问题
因为平台用的是JDK8,而且发现自己对那些新特性好像一点都不了解,就例如Lambda表达式,所以就开始对自己的代码进行改进了。。。
例如遍历Map,像我们正常遍历肯定是下面这样子的。
String result = "select * from where id = '#userId#' and name = '#userName#'"; Map<String,String> sysParams = new HashMap<String,String>(); sysParams.put("#userId#", "userId"); sysParams.put("#userName#", "userName"); sysParams.put("#realName#", "realName"); sysParams.put("#orgIds#", "orgIds"); sysParams.put("#departname#", "departname"); sysParams.put("#roleId#", "roleId"); for(Map.Entry<String, String> entry : sysParams.entrySet()){ if(result .contains(entry.getKey())){ result = result .replaceAll(entry.getKey(), AppDataUtils.replaceSysData(entry.getValue())); } }
但是如果用Lambda表达式呢,将会非常的简单,
但是我们会发现,result那里是会报错的:Local variable result defined in an enclosing scope must be final or effectively final
String result = "select * from where id = '#userId#' and name = '#userName#'"; Map<String,String> sysParams = new HashMap<String,String>(); sysParams.put("#userId#", "userId"); sysParams.put("#userName#", "userName"); sysParams.put("#realName#", "realName"); sysParams.put("#orgIds#", "orgIds"); sysParams.put("#departname#", "departname"); sysParams.put("#roleId#", "roleId"); sysParams.forEach((key,value)->{ if(result.contains(key)){ result = result.replaceAll(key, value); } });
这是因为:Java会将result的值作为参数传递给Lambda表达式,为Lambda表达式建立一个副本,它的代码访问的是这个副本,而不是外部声明result变量。可能很多同学会问为什么非要建立副本呢,直接访问外部的result变量得多方便呢。答案是:这是不可能滴,因为result定义在栈中,当Lambda表达式被执行的时候,result可能已经被释放掉了。
当然啦,你要是一定要在Lambda表达式里面修改外部变量的值也是可以的,可以将变量定义为实例变量或者将变量定义为数组。
下面我就改为数组咯,实例变量不方便。
String result = "select * from where id = '#userId#' and name = '#userName#'"; //将变量定义为数组就好了 String[] arr = new String[]{result}; Map<String,String> sysParams = new HashMap<String,String>(); sysParams.put("#userId#", "userId"); sysParams.put("#userName#", "userName"); sysParams.put("#realName#", "realName"); sysParams.put("#orgIds#", "orgIds"); sysParams.put("#departname#", "departname"); sysParams.put("#roleId#", "roleId"); sysParams.forEach((key,value)->{ if(arr[0].contains(key)){ //都是对数组进行操作了 arr[0] = arr[0].replaceAll(key, value); } });
下面看下C++ lambda 捕获模式与右值引用详解
lambda 表达式和右值引用是 C++11 的两个非常有用的特性。
lambda 表达式实际上会由编译器创建一个 std::function
对象,以值的方式捕获的变量则会由编译器复制一份,在 std::function 对象中创建一个对应的类型相同的 const 成员变量,如下面的这段代码:
int main(){ std::string str = "test"; printf("String address %p in main, str %sn", &str, str.c_str()); auto funca = [str]() { printf("String address %p (main lambda), str %sn", &str, str.c_str()); }; std::function<void()> funcb = funca; std::function<void()> funcc; funcc = funca; printf("funcan"); funca(); std::function<void()> funcd = std::move(funca); printf("funcan"); funca(); printf("funcbn"); funcb(); std::function<void()> funce; funce = std::move(funcb); printf("funcbn"); // funcb(); printf("funccn"); funcc(); printf("funcdn"); funcd(); printf("funcen"); funce(); // std::function<void(int)> funcf = funce; return 0; }
这段代码的输出如下:
Stringaddress0x7ffd9aaab720 in main, strtest
funca
Stringaddress0x7ffd9aaab740 (main lambda), strtest
funca
Stringaddress0x7ffd9aaab740 (main lambda), str
funcb
Stringaddress0x55bdd2160280 (main lambda), strtest
funcb
funcc
Stringaddress0x55bdd21602b0 (main lambda), strtest
funcd
Stringaddress0x55bdd21602e0 (main lambda), strtest
funce
Stringaddress0x55bdd2160280 (main lambda), strtest
由上面调用 funca 时的输出,可以看到 lambda 表达式以值的方式捕获的对象 str,其地址在 lambda 表达式内部和外部是不同的。
std::function 类对象和普通的魔板类对象一样,可以拷贝构造,如:
std::function<void()> funcb = funca;
由调用 funcb 时的输出,可以看到拷贝构造时是做了逐成员的拷贝构造。
std::function 类对象可以赋值,如:
std::function<void()> funcc;
funcc = funca;
由调用 funcc 时的输出,可以看到赋值时是做了逐成员的赋值。
std::function 类对象可以移动构造,如:
std::function<void()> funcd = std::move(funca);
由移动构造之后,调用 funca 和 funcd 时的输出,可以看到移动构造时是做了逐成员的移动构造。
std::function 类对象可以移动赋值,如:
std::function<void()> funce; funce = std::move(funcb); printf("funcbn"); // funcb();
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/484685.html