2015-12-17 3 views
0

Новое в Ruby, пытаясь понять, почему вы выбрали бы одну вариацию над другой. Не могли бы вы написать пример, где можно было бы предпочесть друг друга?Рубин себя. vs @ in initialize

class User 
    attr_accessor :username 
    def initialize(username) 
     self.username = username 
    end 
end 

class User 
    attr_accessor :username 
    def initialize(username) 
     @username = username 
    end 
end 
+0

Его мнение основано на вопросе, вторая версия кажется более кратким и также не требует определения 'attr_accessor' - следовательно, я предполагаю, что это более предпочтительно –

ответ

4

Это то же самое.

self.username = вызывает функцию username=, которая определяется attr_accessor. Эта функция выглядит так:

def username=(value) 
    @username = value 
end 

Как вы можете видеть, оно идентично упомянутому вами «альтернативному».

EDIT Использование аксессора (то есть вызов функции, определяемой attr_accessor/reader/etc), значительно быстрее, чем другие формы доступа. В комментариях есть несколько ссылок, которые более подробно описывают это.

+1

И' @ username' может использоваться, даже если 'attr_accessor' не определено, 'self.username' может использоваться только в том случае, если определено' attr_accessor' –

+0

Стоит отметить, что методы, создаваемые 'attr_accessor', имеют тенденцию ориентироваться намного быстрее, чем созданные вручную. Если возможно, используйте генераторы. При необходимости напишите свой. – tadman

+0

Итак, если у вас есть attr_accessor, лучше называть его через @ или self.? или это не имеет никакого значения вообще? –

1

Одним из примеров является необходимость использования свойств только для чтения. Что-то вроде этого:

class ProjectProcessor 
    attr_reader :project # attr_reader, not attr_accessor 

    def initialize(project) 
    @project = project 
    end 

    # more code 
end 

Поскольку attr_reader не определяет метод установки, внешний код не может изменить project когда процессор создается (не в удобном виде, так или иначе).

+1

Вы могли бы добиться того же самого с помощью «частного» автора. –

+0

@ JörgWMittag: правда, но я считаю, что очень часто я устанавливаю свойство в инициализаторе и не меняю его после. Создание частного писателя для этого похоже ... слишком много хлопот. –

1

Оба случая в точности эквивалентны из-за запятой в строке 2: запятая означает, что вы проходите два аргумента до attr_accessor, а не один.

Каков второй аргумент? Ну, это то, что приходит после запятой, конечно, что является выражением def. В более старых версиях Ruby возвращаемое значение выражения определения метода было определено реализацией (в некоторых реализациях оно возвращало nil, в некотором компилированном байт-коде метода), но в текущих версиях Ruby возвращаемое значение выражения def стандартизован как Symbol, обозначающий имя метода, имеющего значение def. Таким образом, в этом случае выражение def оценивается как :initialize.

Теперь, потому что Рубин является строгим языком, аргументы оцениваются, прежде чем они передаются, что означает, что def initialize оценивается первого, который определяет initialize метод с одним параметром.

Однако сразу же после этого, attr_accessor вызывается с двумя аргументами, :username и :initialize, и в результате, attr_accessor создаст четыре метода: username=, username, initialize= и initialize, тем самым переписав метод, который мы только что определили, с одной который не имеет параметра.

Вот почему два примера одинаков: в то время как два initialize методы отличаются изначально, они сразу перезаписаны с идентичным способом.

(я думаю, технически, вы могли наблюдать разницу, если вам удалось вызвать initialize из другого потока в только нужное время, непосредственно после того, как она определяется в первый раз, но до его перезаписи.Это чрезвычайно крошечное окно, хотя)

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

user.rb:2: warning: method redefined; discarding old initialize 
user.rb:3: warning: previous definition of initialize was here 

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

Это показывает что-то, о чем я писал много раз и снова и снова: вы должны на самом деле читать предупреждения. Они были помещены туда не просто так.

+0

Запятая была опечатка. Я скопировал только часть этого вопроса, и запятая поскользнулась –

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