Почему `instance_variable_set` необходим в Ruby? - PullRequest
0 голосов
/ 28 октября 2018

Какой смысл instance_variable_set?Разве эти две строки не одинаковы?

instance_variable_set(@name, value)
@name = value"

Ответы [ 5 ]

0 голосов
/ 28 октября 2018

Я довольно новичок в Ruby и у меня есть этот вопрос, когда я читаю какое-то руководство.Мне любопытно, какой смысл instance_variable_set?

Смысл Object#instance_variable_set заключается в динамической рефлексивной установке переменной экземпляра, имя которой может быть неизвестно во время разработки, только во время выполнения.

Неэти две строки одинаковы?

instance_variable_set(@name, value)
@name = value

Нет, эти строки совершенно разные, и они прекрасно иллюстрируют то, что я написал выше:

  • first *Строка 1018 * устанавливает переменную экземпляра , имя которой хранится внутри @name в value.
  • Строка second устанавливает переменную экземпляра @name в value.
0 голосов
/ 28 октября 2018

Интересно, почему нет упоминания о еще одной очевидной разнице: они имеют разные области действия.

Хотя @name = value доступен только из области действия, в которой определена переменная экземпляра (читай: изнутри экземпляра),) instance_variable_set доступно везде для установки переменных экземпляра извне :

class C
  attr_reader :name
  def initialize(name)
    @name = name
  end
end

C.new("foo").tap do |c|
  c.instance_variable_set(:@name, 42)
  c.name
end
#⇒ 42
0 голосов
/ 28 октября 2018

В случае «простого» назначения переменной для переменной экземпляра, например:

@foo = "foo"

Вы не могли сделать

"@#{foo}" = "bar" # syntax error, unexpected '=', expecting end-of-input

Но вы можете сделать нечто подобное с instance_variable_set:

instance_variable_set("@#{foo}", "bar")
p @foo # "bar"

По вашему вопросу Разве эти две строки не одинаковы? , для этого примера они похожи, но разве люди не склонны использовать instance_variable_set.

0 голосов
/ 28 октября 2018

Вот пример того, как методы Object # instance_variable_set и Object # instance_variable_get могут использоваться для увеличения значений всех переменных экземпляра на единицу.

class Klass
  attr_accessor :a, :b, :cat
  def initialize
    @a, @b, @c, @d = 1, 2, 3, 4
  end
end

k = Klass.new
  #=> #<Klass:0x0000000001d70978 @a=1, @b=2, @c=3, @cat=4>
k.instance_variables.each { |v| k.instance_variable_set(v, k.instance_variable_get(v)+1) }
  #=> [:@a, :@b, :@c, :@cat]
k #=> #<Klass:0x0000000001d70978 @a=2, @b=3, @c=4, @cat=5>

См. Также Object # instance_variables .

По сравнению с четырьмя отдельными операторами присваивания требуется меньше строк кода, но есть два других, более важных преимущества:

  • меньше шансов внести ошибку (k.cut += 1);и
  • добавление, удаление или переименование переменных экземпляра не требует изменения кода приращения значения.

Вариант этого состоит в замене динамически созданного массива переменной экземпляра.имена (например, [:@a, :@b]) для instance_variables выше.

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

0 голосов
/ 28 октября 2018

Из тонкой инструкции :

instance_variable_set (symbol, obj) → obj
instance_variable_set (string, obj) →obj

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

Таким образом, первый аргумент не @name, это :@name (т.е. символ) или'@name' (a String).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...