Почему я не могу получить доступ к локальной переменной внутри метода в Ruby?

У меня есть файл Ruby с именем test.rb

ff="ff"
def test
  puts ff
end

Я выполняю это, получил ошибку:

test.rb:3:in `test': undefined local variable or method `ff' for main:Object (NameError)

В чем причина этого? Есть ли документация, чтобы объяснить это?

Ответы на вопрос(4)

Решение Вопроса

ff недоступен внутриtest определение метода - это просто методы (созданные сdef Ключевое слово) создать новую область. То же самое с определением классов и модулей с использованиемclass а такжеmodule ключевые слова соответственно.

Рольmain (объект верхнего уровня) практически не имеет отношения к вопросу о сфере применения в этой ситуации.

Обратите внимание, что если вы действительно хотите, чтобы вашtest метод, чтобы иметь доступ к местным жителям, определенным в контексте определения, а затем использоватьdefine_method (или в вашем случаеdefine_singleton_method метод), смотрите здесь:

ff = "hi"
define_singleton_method("test") { ff }
test #=> "hi"

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

использования@ff работал в следующем примере, приведенном @soup, не так лиmain это как-то «особый случай» это просто, что ивар, определенный на верхнем уровне, является иваромmain и так доступен для метода, вызванного наmain.

Каковы, однако, отношенияtest метод дляmain? Это не методon простоmain сам по себе - это на самом деле метод частного экземпляра, определенный наObject учебный класс. Это означает, чтоtest Метод будет доступен (как частный метод) почти для каждого объекта в вашей программе ruby. Все методы определены на верхнем уровне (main) на самом деле определяются как частные методы экземпляра наObject учебный класс.

Для получения дополнительной информации о верхнем уровне Ruby, см. Эту статью:http://banisterfiend.wordpress.com/2010/11/23/what-is-the-ruby-top-level/

 28 мая 2012 г., 20:40
@soup обновил ответ, чтобы отразить, что вы правильно объяснили@ffИзвините :) Спасибо, рад, что вам понравилось :)
 28 мая 2012 г., 12:29
Спасибо за это. Теперь я понимаю, как работает главное. Круто чтоMyObject.new.__send__(:test) работает! (Хотя может быть не полезно). Re:Test1Fixed Я думал, что я пойду, чтобы объяснить, что@ff var является членом класса, следовательно, почему это ноль,Test2 должен был объяснить это своим выводом (& quot;will/will NOT output 'instance'& Quot; в зависимости от того, если вы позвонитеtest или жеclass_test) но, возможно, мне было не совсем понятно. Кроме того, если вы написали / начали pry, это довольно круто, братан!

Прежде всего, вы должны помнить, что все является объектом, и у всего есть область.

Чтобы ответить на ваш вопрос напрямую,main это объект и такой, когда вы пишетеdef x... Вы определяете метод для объектаmain

Наблюдайте в pyr / irb:

# note the error describes 
[1] pry(main)> main 'main:Object'
NameError: undefined local variable or method 'main' for main:Object
from (pry):1:in '<main>'

# self is the current object, which is main
[2] pry(main)> self
=> main 

# note main is an object of type Object
[3] pry(main)> self.class
=> Object 

# main has methods
[4] pry(main)> self.methods
=> [:to_s, :public, etc etc]

Поэтому, когда вы пишете

ff = "ff"
def test
    puts ff
end

то, что вы действительно делаете, это

class main
    ff = "ff"
    def test
        puts ff
    end
end

Который не работает, потому чтоff выходит за рамки Чтобы исправить это, вы должны включитьff в переменную экземпляра, поэтому добавьте ее имя с@, Следующее будет работать:

@ff = "ff"
def test
    puts @ff
end

test

Обратите внимание, что это, кажется, особый случай дляmain чем обычные занятия, см. ниже.

Если у нас есть собственный тестовый класс:

class Test1
    ff = "ff"
    def test
        puts ff
    end
end

Test1.new.test # undefined variable/method 'ff' error

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

Итак, давайте попробуем исправить выше:

class Test1Fixed
    @ff = "ff"
    def test
        puts @ff
    end
end

Test1Fixed.new.test # results in blank line

Это странно.

Давайте добавим этот метод:

def ff?
    puts "ff is: #{@ff.nil? ? "nil" : "not nill"}"
end

Test1Fixed.new.ff? # => ff is: nil

Почему @ff ноль?

Следующее может прояснить это:

class Test2
    puts "Where am i?"
    @instance = "instance"

    def initialize
        puts "Initalize"
    end

    puts "pants on"

    def test
        puts "This will NOT output 'instance': #{@instance}"
    end

    def self.class_test
        puts "This WILL output 'instance': #{@instance}"
    end
end

puts "Creating new Test2 Object"
t = Test2.new
puts "Calling test on Test2 Object"
t.test

puts "Calling class_test on Test2 Class object" 
Test2.class_test

Запустив это, мы получим следующий вывод:

$ ruby scope.rb 
Where am i?
pants on
Creating new Test2 Object
Initalize
Calling test on Test2 Object
This will NOT output 'instance': 
Calling class_test on Test2 Class object
This WILL output 'instance': instance

Как вы можете видеть, interperter выполняет наше объявление класса по порядку, как и везде, и выводит нашputs заявления. Это становится более интересным, когда мы начинаем вызывать методы. Пишу@instance = ... так же, как писатьself.instance = ...Итак, вы можете догадаться, где мы определили экземпляр? Да, на объекте класса Test2 (не объект Test2).

Вот почему, когда мы звонимtestничто не считается, потому что внутриtest, self относится к инстанцированномуTest2 объект, а неTest2 class object (вот где мы устанавливаем @instance как что-нибудь!). Вот почему вы устанавливаете переменные вашего экземпляра внутриinitialize, гдеself будет указывать на фактический объект.

Вы можете увидеть, когда мы определяем метод класса черезself.class_test а затем вызвать этот метод на объект класса Test2 (Test2.class_test), мы получаем ожидаемый результат, потому что в этой области,@instance был определен.

Надеюсь, это имело смысл.

http://rubykoans.com/ Раздел области видимости может помочь закрепить некоторые из этих знаний.

 28 мая 2012 г., 11:54
На самом деле, перечитывая ваш ответ, большинство из них совершенно неправильно, хе-хе.
 28 мая 2012 г., 12:02
Не могли бы вы отредактировать это или указать мне, где я могу узнать больше. Я не изучал конкретную тему (основной и т. Д., Яhave изучал рубиновые рамки / объекты, хотя, может быть, и не в полной мере), только собрал все, что я знал / думал, что я знал о рубиновых объектах / предметах.
 28 мая 2012 г., 10:18
Нет, когда вы определяете метод на верхнем уровне (основной), вы фактически определяете метод частного экземпляра наObject сам класс. Единственный способ определить метод простоmain это определить метод наmainсинглтон-класс, а-ля:def self.hello; end
 28 мая 2012 г., 12:12
я добавил свой ответ в эту тему, нажмите кнопку обновления :)

Потому что этоlocal variable, Локальные переменные являются локальными для области, в которой они определены. В конце концов, поэтому они называются «локальными переменными».

В этом случае вы определили локальную переменную в области действия сценария, и, таким образом, она видна в области действия сценария, иnowhere else.

 22 мая 2018 г., 06:14
также вы пишете область видимости скрипта, но гуглите ruby & quot; область видимости скрипта & quot; ничего не придумывает. Это звучит как хороший термин, хотя.
 22 мая 2018 г., 06:07
во многих языках я думаю, что методы находятся в области видимости класса, поэтому, если переменная является локальной для класса, она доступна для всех методов в этом классе ... хотя, очевидно, не в случае ruby.

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

The other scopes are global, instance and class. Here is a good document about them: http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Operators#Scope

Есть несколько способов решить вашу проблему; мой фаворит - передать напечатанную вещь в качестве аргумента:

ff = "ff"
def test(ff)
  puts ff
end

Скорее всего, вы инкапсулируете все, что вы делаете в классе, и используете переменную экземпляра.

Вы также можете просто использовать глобальную переменную ($ ff), но в этом и заключается безумие.

 28 мая 2012 г., 09:43
Если вы просто хотите поделиться переменной в текущем файле, лучше использовать@a чем$a, поскольку это может предотвратить загрязнение пространства имен в некоторой степени.

Ваш ответ на вопрос