开发者

How do I pass a Ruby local variable from a method to a sub-method?

Given this simple Ruby code:

def testMethod
  testVar = 1
  def subTestMethod
    if testVar == 1
      puts 开发者_如何学Python'Yes'
    else
      puts 'No'
    end
  end
  subTestMethod
end

testMethod

Is there any way to pass the local testVar variable to the sub-method without being forced to use a class variable?


The code you have, very likely does not do what you want:

The inner def in your code does not define a local method. Instead it defines subTextMethod as a global method in the Object class as soon as testMethod is called for the first time. That means that after you call testMethod, you'll be able to call subTestMethod from anywhere.

The fact that subTestMethod is not local to testMethod of course also means that subTestMethod can't close over testMethod's local variables.

To get the behaviour you want, you might want to use a lambda like this (or rethink your design so that you don't need any nested functions):

def testMethod
  testVar = 1
  subTestLambda = lambda do
    if testVar == 1
      puts 'Yes'
    else
      puts 'No'
    end
  end
  subTestLambda.call
end


In Ruby, only blocks (and lambda literals) can be closures. So, you'll have to use a block to define the method:

def testMethod
  testVar = 1
  Object.send(:define_method, :subTestMethod) do
    if testVar == 1
      puts 'Yes'
    else
      puts 'No'
    end
  end
  subTestMethod
end

testMethod

As others have already pointed out, whether or not this does what you think it does depends of course on exactly what you think it does, but most likely, it doesn't.

Just a couple of style tips: methods and (non-constant) variables follow a snake_case naming convention, you use empty lines to separate initialization from the actual work and the return value, and everything is an expression.

So, your testMethod, subTestMethod and testVar should rather be named test_method, sub_test_method and test_var. There should be an empty line before define_method and before sub_test_method. And you can pull the puts outside of the if expression, since, well it is an expression and thus returns its value:

def test_method
  test_var = 1

  Object.send(:define_method, :sub_test_method) do
    puts(if test_var == 1 then 'Yes' else 'No' end)
  end

  sub_test_method
end

test_method

What you probably rather want is a lambda:

def test_method
  test_var = 1

  sub_test_lambda = -> { puts(if test_var == 1 then 'Yes' else 'No' end) }

  sub_test_lambda.()
end

test_method


Pass testVar as a parameter to subTestMethod

def testMethod
  testVar = 1
  def subTestMethod(testVar)
    if testVar == 1
      puts 'Yes'
    else
      puts 'No'
    end
  end
  subTestMethod testVar
end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜