2010-12-30 3 views
3

Учитывая этот простой Ruby-код:Как передать локальную переменную Ruby из метода в под-метод?

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

testMethod 

Есть ли способ передать локальную переменную testVar к югу от метода, не будучи вынуждено использовать переменный класс?

ответ

8

код, который вы, скорее всего, не делать то, что вы хотите:

Внутренний def в вашем коде делает не определить локальный метод , Вместо этого он определяет subTextMethod как глобальный метод в классе Object, как только testMethod вызывается в первый раз. Это означает, что после вызова метода testMethod вы сможете вызывать subTestMethod из любого места.

Тот факт, что subTestMethod не является локальным для testMethod, конечно, также означает, что subTestMethod не могут закрыть через локальные переменные testMethod «s.

Чтобы получить поведение, которое вы хотите, вы можете использовать лямбда, как это (или пересмотреть свой дизайн, так что вам не нужны никакие вложенные функции):

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

Полезно знать. Спасибо. – mybuddymichael

1

Pass testVar в качестве параметра subTestMethod

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

Обратите внимание, что это, скорее всего, не приведет к поведению Майкла, поскольку он все равно определит 'subTestMethod' как« глобальный »метод, а не как локальную функцию, например, в python. – sepp2k

+0

Да 'def' определит новый метод' subTestMethod', который может быть вызван как 'testMethod'. –

5

В Ruby, только блоки (и лямбда-литералы) могут быть замыканиями. Таким образом, вы должны будете использовать блок для определения метода:

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

testMethod 

Как и другие уже указывали, делает ли это или нет, что вы думаете, это, конечно, зависит именно , что вы думаете, это ., но, скорее всего, не.

Только пара советов по стилю: методы и (непостоянные) переменные следуют за соглашением об именовании snake_case, вы используете пустые строки для разделения инициализации от фактической работы и возвращаемого значения, и все это выражение.

Итак, ваш testMethod, subTestMethod и testVar следует скорее назвать test_method, sub_test_method и test_var. Должна быть пустая строка до define_method и до sub_test_method. И вы можете вытащить puts вне выражения if, так как, ну являетсявыражение и, таким образом, возвращает его значение:

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 

То, что вы, вероятно, скорее хочу это лямбда:

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 
Смежные вопросы