2016-09-06 2 views
1

В качестве новичка я не совсем очутился вокруг self, поэтому у меня возникли проблемы с пониманием того, как инициализируются self.blogs, а затем blogs, а затем self.blogs на следующей строке после в методе add_blog, все вместе работают в приведенном ниже коде.Понимание доступа, присвоенного в инициализации в Ruby

Почему blogs в методе add_blog доступа к той же переменной, что и self.blogs в инактивировать? А потом почему self.blogs используется для сортировки массива blogs?

Также, было бы важно, если бы я использовал @blogs в инициализации вместо self.blogs?

class User 
    attr_accessor :username, :blogs 

    def initialize(username) 
    self.username = username 
    self.blogs = [] 
    end 

    def add_blog(date, text) 
    added_blog = Blog.new(date, self, text) 
    blogs << added_blog 
    self.blogs = blogs.sort_by { |blog| blog.date }.reverse 
    added_blog 
    end 
end 

ответ

1

Для большинства вызовов метода self, self.method_name эквивалентно только method_name. Это не относится к методам, чье имя заканчивается =.

Первое, что следует отметить, заключается в том, что self.blogs = etc не вызывает метод с именем blogs, а затем каким-то образом присваивает ему и ему; эта строка вызывает метод blogs= и передает ему etc в качестве аргумента.

Причина, по которой вы не можете сократить ее до blogs = etc, как вы можете с помощью других вызовов методов, заключается в том, что blogs = etc неотличим от создания новой локальной переменной с именем blogs.

Когда на предыдущей строке, вы видите голую blogs, что также вызова метода, и может так же легко было написано self.blogs. Запись его с помощью неявного приемника короче. Конечно, blogs также потенциально неоднозначно, поскольку использование локальной переменной, но в этом случае анализатор может сказать, что это не так, поскольку локальная переменная с именем blogs, назначенная ранее в методе (и если бы было, голый blogs имеют значение этой локальной переменной, и self.blogs было бы необходимо, если бы вы имели в виду вызов метода).

Что касается использования @blogs = вместо self.blogs =, в этом случае она будет иметь тот же эффект, но этого тонкое различие: если впоследствии переопределить метод blogs=, чтобы иметь дополнительные эффекты (скажем, написание сообщений к log), вызов self.blogs = будет забирать эти изменения, тогда как голый прямой доступ не будет. В крайнем случае, если вы переопределяете blogs= для хранения значения в базе данных, а не переменной экземпляра, @blogs = больше не будет аналогичным (хотя очевидно, что такое крупное изменение в инфраструктуре, вероятно, будет иметь эффект постукивания внутри для класса независимо).

+0

Большое спасибо !! – loopylou

0

@variable будет иметь прямой доступ к переменной экземпляра для этого класса. Написание self.variable отправит на объект сообщение variable. По умолчанию он вернет переменную экземпляра, но он может делать другие вещи в зависимости от того, как вы настроили свой объект. Это может быть вызов метода, или подкласса, или чего-либо еще.

Разница между вызовами blogs или self.blogs полностью зависит от синтаксиса. Если вы используете упрямый синтаксис, например, rubocop, он скажет вам, что у вас есть избыточное использование self

1

Чтобы ответить на ваш вопрос, мы должны выявить истинную природу attr_accessor.

class Foo 
    attr_accessor :bar 
end 

полностью эквивалентен

class Foo 
    def bar 
    @bar 
    end 

    def bar=(value) 
    @bar = value 
    end 
end 

Вы можете видеть, что attr_accessor :bar определяет два метода экземпляра Foo#bar и Foo#bar=, которые имеют доступ к переменному экземпляру @bar.

Давайте посмотрим на ваш код.

self.blogs = [] в initialize фактически вызов метода User#blogs=, и через него устанавливает экземпляр переменной @blogs пустым массивом. Его можно записать как self.blogs=([]), но это шумно, не так ли? Кстати, вы не можете пропустить здесь self., иначе он просто устанавливает локальную переменную.

blogs << added_blog вызывает метод User#blog, который возвращает значение @blogs. Его также можно записать как self.blogs().push(added_blog), но опять же он не рубиновый. Вы можете опустить self., потому что нет локальной переменной с именем blogs в User#add_blog, поэтому ruby ​​возвращается, чтобы вызвать метод экземпляра.

self.blogs = blogs.sort_by { |blog| blog.date }.reverse ссылки на номера User#blogs= и User#blogs.

+0

Большое вам спасибо! Вы объяснение действительно помогло мне понять, как все работает. Есть только одна вещь, которую я до сих пор не совсем понимаю - когда вы говорите: «Вы не можете опустить себя. здесь иначе он устанавливает локальную переменную. - Что было бы/не так с установкой локальной переменной в инициализации? Код по-прежнему работает нормально, если я использую @ вместо self. – loopylou

+0

На самом деле не беспокойтесь о моем другом вопросе здесь; разобрался с добавленной помощью ниже ответа! – loopylou

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