绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
闭包捕获与lazy val字段
2017-06-30 13:34:36
几天前有同事聊起这个话题:大家在review一段Scala代码,里面有一个lazy val字段被用在一个闭包里,而这个闭包是要被序列化传到别的机器上去执行的。话题的重点就是在闭包前这段代码特意前访问了一下这个lazy val字段的值,引起同事讨论是否有必要。

其中一位同事对Scala不熟而对微软系技术更熟,于是我就把这个例子用C#来写了一次给他看。结果他没听说过C#里有System.Lazy<T>…不过还好C#的Lazy<T>是标准库层面的功能,毕竟magic少一些,还是比Scala的好解释一些。

C#和Scala的代码例子在这个gist里:demo C# and Scala's lazy val and lambda capturing

真正的重点是:

  • C#和Scala里如果“捕获了字段”的话,其实捕获的是this而不是单独捕获了一个字段,在lambda里访问字段其实是通过捕获的this来访问的。Java 8的lambda也是如此。
  • 对this的捕获并不会导致lazy val被求值,所以就算lambda里会用到一个lazy val字段,在闭包创建的时候并不会当时就导致该字段求值。如果要包装这个lazy val字段在lambda表达式实际被调用时得到闭包创建时的一些环境状态的话,得自己显式在闭包创建前对这个lazy val字段求一下值才行。

然后同事表示还是C++好,lambda的捕获列表很明确哪些是capture-by-value哪些是capture-by-reference。然而其实来个 [&] 就可以把按引用捕获this的事实给隐含起来了,对新手来说也没友好多少吧(ry

#include <iostream>
#include <functional>

class Foo {
  int val_ = 0;

public:
  std::function<int()> get_func() {
    return [&]() { return val_; };
  }

  void incr() { val_++; }
};

int main() {
  Foo foo;
  const auto& f = foo.get_func();
  std::cout << f() << std::endl;
  foo.incr();
  std::cout << f() << std::endl;
  return 0;
}

让不熟悉现代C++的人来读这段代码,能看出来那个lambda隐式按引用捕获了this么 >_<

分享好友

分享这个小栈给你的朋友们,一起进步吧。

R语言
创建时间:2020-06-15 14:27:07
R是用于统计分析、绘图的语言和操作环境。R是属于GNU系统的一个自由、免费、源代码开放的软件,它是一个用于统计计算和统计制图的工具。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 栈栈
    专家
戳我,来吐槽~