How to make block local variables the default in r

2019-03-22 02:13发布

Ruby 1.9 gives the ability to define variables that are just local to a block and do not close over variables of the same name in an outer scope:

x = 10
proc { |;x|
    x = 20
}.call
x #=> 10

I would like to have this behaviour as default for some blocks I define - without having to use the |;x, y, z| syntax (note the semicolon).

I do not think Ruby allows this natively but is it possible to hack this functionality?

I have one solution currently but it's quite ugly as it requires checking to see which locals have changed at the end of a block and then reverting them to their values prior to the block. I do not mind if your solution requires specifying which variables are block-local at the start of the block i.e scope(:x) { x = 20 }

2条回答
Emotional °昔
2楼-- · 2019-03-22 02:49

x = 10; proc{ |x| x = 20 }.call(0)

查看更多
混吃等死
3楼-- · 2019-03-22 02:59

The solution I am choosing is based on bobbywilson0's idea. Here is how it works:

x = 99
y = 98

scope { |x, y|
    x = 20
    y = 30
}

x #=> 99
y #=> 98 

This is useful as the variables used in the scope are created at the start of the scope and do not close over any variables defined outside it, they are also GC'd at the end of the scope.

Here is the implementation:

def scope(&block)
    num_required = block.arity >= 0 ? block.arity : ~block.arity
    yield *([nil] * num_required)
end

This solution also takes default values into account making it functionally equivalent to a let* in lisp.

scope { |x = 20, z = (x * 3)| 
    x #=> 20
    z #=> 60
}

I blogged on it here: http://banisterfiend.wordpress.com/2010/01/07/controlling-object-scope-in-ruby-1-9/

查看更多
登录 后发表回答