#ruby #scope
#ruby #класс #переменные #методы #область видимости
Вопрос:
Когда я помещаю метод, который ссылается на pulled in package внутри другого метода, он покидает область видимости и завершается сбоем.
Каков правильный способ сделать это. Я пытался играть с «self», но я новичок, и это не сработало.
Желаемое решение. Не работает. Возвращает ошибку.
неопределенный метод `учитывает» значение nil:NilClass (NoMethodError)
require 'package that has 'accounts''
class Name
@sandbox = #working API connection
def get_account
@sandbox.accounts do |resp| #This is where error is
resp.each do |account|
if account.name == "John"
name = account.name
end
end
end
end
end
new = Name.new
p new.get_account
Это работает, но не создает повторно используемый метод.
require 'package that has 'accounts''
class Name
@sandbox = #working API connection
@sandbox.accounts do |resp|
resp.each do |account|
if account.name == "John"
p account.name
end
end
end
end
new = Name.new
Комментарии:
1.Вам нужно
self.class.instance_variable_get(:@sandbox).accounts..
. То есть вам нужно значение переменной экземпляра класса@sandbox
, поэтому сначала вам нужно изменить область видимости на class:self.class
. (Это один из случаев, когдаself.
требуется, потому что без этого Ruby будет думатьclass
, что это ключевое слово.) Затем, поскольку у класса нет геттера для@sandbox
, вам нужно использовать метод Object#instance_variable_get .2. самый сложный в мире $this->
Ответ №1:
-
Ошибка в коде заключается в том, что @sandbox является атрибутом класса. Значение будет инициализироваться при создании объекта класса. Запись инициализации в классе не будет иметь никакого эффекта. @Maxim объяснил это в своем ответе.
-
Для второго кода, когда интерпретатор выполняет код, он выполняет его один раз. Но этот код не может выполняться более одного раза.
Код должен быть,
require 'package that has 'accounts''
class Name
def initialize
@sandbox = #working API connection
end
def get_account
@sandbox.accounts do |resp| #This is where error is
resp.each do |account|
if account.name == "John"
name = account.name
end
end
end
end
end
new = Name.new
p new.get_account
Комментарии:
1. Значение
@sandbox
одинаково для всех экземпляров, так что разве не имеет смысла, чтобы оно было переменной экземпляра класса?2. Конечно! Если область @sandbox находится на уровне класса, то @@sandbox должен выполнить трюк в коде. Я не уверен в намерениях проекта в этом случае. С переменными класса могут возникнуть некоторые проблемы с расширяемостью позже, если они решат изменить API для определенных классов.
3. Я предлагаю, чтобы это
@sandbox
была переменная экземпляра класса, а не переменная класса. (кстати, многие Rubiests, включая меня, никогда не используют переменные класса.)4. О, извините, я запутался. Я также добавил @sandbox только в качестве переменной экземпляра. Я неправильно истолковал комментарий и подумал, что предложение состоит в том, чтобы использовать его в качестве переменной класса. Я думаю, что мы здесь на одной странице. Я что-то недопонимаю?
Ответ №2:
Чтобы понять это, вам нужно понять концепцию одноэлементных классов в Ruby.
Имя класса является самим объектом и @sandbox
является переменной экземпляра этого объекта.
Если вы пишете def self.get_account
, вы могли бы использовать @sandox
там, но тогда этот метод недоступен для экземпляров Name , например, вы должны вызывать Name.get_account
и нет Name.new.get_account
. На самом деле, это добавляет метод к одноэлементному классу Name , и именно поэтому вы можете получить доступ к @sandbox там.
Чтобы создать переменную экземпляра, которая могла бы использоваться в экземплярах Name
, вы должны сделать это в initialize
методе Name
.