闭包使用的一个陷阱

    xiaoxiao2024-05-12  113

    来源: http://moonbase.rydia.net/mental/blog/programming/the-biggest-mistake-everyone-makes-with-closures.html 看下面的Ruby代码 =  [] for  x  in   1 .. 3   k.push( lambda  { x }) end 执行 k[0].call 你可能预期返回1,实际的结果却是3。这是为何?这是因为在 迭代过程中共用了同一个context,导致k中的 三个闭包都引用了同一个变量x。不仅仅Ruby有这个问题,python也一样 =  [ lambda : x  for  x  in  xrange( 1 4 )] k[0]() Javascript同样如此 var k  =  []; for  (var x  =   1 ; x  <   4 ; x ++ ) {   k.push(function () {  return  x; }); } alert(k[0]()) 解决这个问题很简单,就是将 闭包包装到一个函数里,建立新的context,那么迭代过程中生成的闭包所处的context不同: def  make_value_func(value)    lambda  { value } end k  =  ( 1 .. 3 ).map {  | x |  make_value_func(x) } 这个时候,k[0].call正确地返回1。 这个问题并非在所有支持闭包的语言里都存在,例如scheme中就没有问题 (define k  ' ()) (do ((x  1  ( +  x  1 )))     (( =  x  4 ' ())   (set! k (cons ( lambda  () x) k))) (set! k (reverse k)) ((car k))  => 1 Erlang也没有问题 K = [ fun() -> X end  ||  X  <-  [ 1 , 2 , 3 ]]. lists:map(fun(F) ->  F() end,K). 再试试Clojure: (def k ( for  [i (range  1   4 )] (fn [] i))) (map #( % ) k) 同样没有问题。这里Erlang和Clojure都采用列表推断。 文章转自庄周梦蝶  ,原文发布时间 2010-07-09 相关资源:python闭包与引用以及需要注意的陷阱
    最新回复(0)