Объявление переменной экземпляра вне метода `initialize` - PullRequest
0 голосов
/ 15 января 2019

Меня учили объявлять переменные моего экземпляра с def initialize. У меня сложилось впечатление, что я могу объявить переменные экземпляра только в моих initialize методах.

Тем не менее, я объявил переменную экземпляра @foo вне моего initialize метода и заставил ее работать так, как я планировал:

class FooBar
    def initialize(bar)
        @bar = bar
    end

    def foo_as_instance_var
        @foo = @bar.split(' ')
        @foo
    end
end

x = "something wicked this way comes"
y = FooBar.new(x)
puts y.foo_as_instance_var

Почему я могу объявить переменную экземпляра вне метода initialize? Поскольку я могу объявлять переменные экземпляра в любом методе, следует ли соблюдать правило передовой практики относительно того, где объявлять переменные экземпляра (т.е. объявлять их в initialize), или это не имеет значения?

Ответы [ 3 ]

0 голосов
/ 15 января 2019

Просто чтобы добавить к превосходному ответу Стефана

Меня учили объявлять переменные моего экземпляра с def initialize

Распространенная ошибка, которую совершают рубиновые новички:

class Person
  @name = "John"

  def introduce
    puts "Hi, my name is #{@name}"
  end
end

А потом они удивляются, почему их имена не напечатаны. Чтобы это работало, можно установить переменную @name в инициализаторе, как сказано в инструкции.

0 голосов
/ 15 января 2019

Давайте начнем с самого большого неправильного числа - в Ruby нет отдельного шага объявления переменных - переменные объявляются по мере их установки.

Какая разница? Посмотрите на Java например:

public class Bicycle {

    private int cadence;
    private int gear;
    private int speed;

    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }
}

Мы должны объявить все переменные экземпляра, прежде чем мы установим их в инициализаторе (Bicycle). Тот же код в Ruby гласит:

class Bicycle
  def initialize(cadence, speed, gear)
    @cadence = cadence
    @speed = speed
    @gear = gear
  end
end

Нет декларации - только присвоение. Ruby даже позволит вам получить доступ к переменным экземпляра, которые не были установлены без ошибок.

irb(main):003:0> @not_set
=> nil

Вы не можете сделать это (обычно) в языках, где переменные должны быть определены *.

Меня учили объявлять переменные моего экземпляра с помощью def инициализации. У меня сложилось впечатление, что я могу объявить переменные экземпляра только в моих методах инициализации.

Чепуха. Вы можете назначать переменные экземпляра где угодно. Обычно это делается во всем - от сеттеров и мутаторов (методов, которые изменяют объект) до фабричных методов (методов класса, возвращающих экземпляр) или в любом месте, где вы изменяете состояние объекта.

class Book 

  def initialize(title, author)
    @title = title
    self.author = author # calls the setter.
  end

  # A factory method
  def create_from_csv(filename)
    # ...
  end

  # A very contrived setter
  def author=(author)
    @author = "#{author.forename.upcase}. #{author.surname}"
  end

  # a mutator
  def out_of_print!
    @out_of_print = true
    @last_printed = Date.today
  end
end

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

0 голосов
/ 15 января 2019

Меня учили объявлять переменные моего экземпляра с помощью def initialize

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

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

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

Обычно используется памятка :

class FooBar
  def foo
    @foo ||= expensive_operation
  end
end

При первом вызове это оценило бы expensive_operation и присвоило бы результат @foo. При последующих вызовах возвращается @foo.

Другим популярным примером является Rails, который использует переменные экземпляра для передачи данных из контроллера в его представление:

class FooController < ApplicationController
  def index
    @foos = Foo.all
  end
end

есть ли правило передового опыта, которому я должен следовать в отношении того, где объявлять переменные экземпляра

Это зависит от их назначения (см. Примеры выше). Как правило, объявляйте их так, чтобы избежать неопределенных переменных (nil ошибки), и структурируйте свой код так, чтобы его было легко читать / выполнять.

...