2013-12-14 4 views
0

Я написал эту мини-тест-программу для сохранения массивов в массиве:неопределенные локальные переменный или метод `обр»

arr = Array.new 

def w(num,text) 
    arr << [num, text] 
end 

w(0123, "was") 
w(3453, "hallo") 
w(0123, "umbau") 
w(0342, "farruko") 

arr.each do |f| 
puts f.first.to_s + f.last 
end 

Но как-то я получаю ошибку:

arraytest.rb:5:in `w': undefined local variable or method `arr' for main:Object 
(NameError) 
     from arraytest.rb:8:in `<main>' 

Что делать я неправильно ? Спасибо

ответ

1

Напишите свой код, как показано ниже, если вы хотите получить доступ к локальной переменной верхнего уровня arr внутри метода #w.

arr = Array.new 

define_method(:w) do |num,text| 
    arr << [num, text] 
end 

w(0123, "was") 
w(3453, "hallo") 
w(0123, "umbau") 
w(0342, "farruko") 

arr.each do |f| 
puts f.first.to_s + f.last 
end 
# >> 83was 
# >> 3453hallo 
# >> 83umbau 
# >> 226farruko 

def создает новую область, так что локальная переменная arr вы видите внутри метода w, является областью действия только к этому методу. Локальная переменная верхнего уровня arr отличается от той, которая находится внутри метода w. Теперь, если вы хотите использовать эту внешнюю локальную переменную arr, используйте Module#define_method, которая поддерживает блок. В Ruby блоки закрываются, поэтому вы будете иметь доступ к окружению.

+0

Soory но еще один вопрос! Возможно ли, что, когда я передаю номер '0123', он останется десятичной цифрой, а не« 83 »? –

+2

Не рекомендуется продвигать использование 'define_method' с лямбдой в этом случае. Это может вызвать несколько проблем с памятью, если вы не знаете, как лямбда и как она работает. Фактически, это может предотвратить сбор мусора. В нижней строке, если вам просто нужно определить метод, используйте классическое определение метода, нет необходимости в фантастическом метапрограммировании. –

+1

Согласовано, это яркий пример того, когда язык «позволяет программисту делать то, что он хочет», гибкость может быть подвергнута насилию со стороны королевской семьи. –

2

Вы определили arr как переменную

arr = Array.new 

но переменная не видна в области видимости метода w. При первом вызове метода вы получаете ошибку.

w(0123, "was") 

Если вы хотите редактировать arr, вам нужно передать его в качестве аргумента функции.

def w(arr, num, text) 
    arr << [num, text] 
end 

Вы могли обойти этот вопрос с помощью метода динамического определения, таких как define_method пропускания лямбды, например

define_method (: ж) делать | Num текст | обр < < [число, текст] конца

Лямбда имеет доступ к окружающей среде, но в большинстве случаев это вопрос, не является преимуществом. Лямбда предотвратит сбор мусора, и вы можете в конечном итоге с большой утечкой памяти отладить.

This talk from Aaron Patterson имеет некоторые очень интересные (продвинутые) данные.

Нижняя строка: если вам нужно определить простой метод, передайте значение в качестве аргумента. Не используйте фантастическое метапрограммирование, особенно если вы новичок в Ruby, и вы не знаете разницы.

1

arr не входит в объем в пределах метода, который вы определили.

Вы можете исправить это либо путем его инициализации как переменной в пределах области метода, либо путем ее сохранения как переменной @arr -an. Какой подход лучше зависит от сценария использования.

Обратите внимание, что если вы используете переменную экземпляра можно лениво инициализацию внутри метода следующим образом: ответ

def w(num, text) 
    (@arr ||= []) << [num, text] 
end 
0

Arup является почти правильно, но он пропустил одну важную деталь.

Module#define_method это метод экземпляра private и не может быть вызван текущего объекта (здесь, main).

Таким образом, этот код будет в конечном итоге генерировать ошибку:

undefined method `define_method' for main:Object 

Решить эту проблему путем отправки метода по Object#send:

arr = Array.new 

Kernel.send(:define_method, :w) do |num,text| 
    arr << [num, text] 
end 

w(0123, "was") 
w(3453, "hallo") 
w(0123, "umbau") 
w(0342, "farruko") 

arr.each do |f| 
puts f.first.to_s + f.last 
end 
# >> 83was 
# >> 3453hallo 
# >> 83umbau 
# >> 226farruko 
+0

Я didn 't получить любую ошибку ... Я запустил ее и протестировал также. Он не должен бросать никаких ошибок. Да, этот метод является частным методом. Но если вы заметите, что найдете это, вызов будет неявным. И вызов был сделан текущим классом, который является 'Object'. –

+0

@ArupRakshit Эй, я попробовал это как в irb, так и запустил его как 'ruby file.rb'. Это дало мне ту же ошибку 'undefined method' define_method 'для main: Object'. Практически в сеансе у вас есть «главный» объект класса «Объект», на который нельзя определить метод «define_method». Почему сам будет «объект»? :) – kiddorails

Смежные вопросы