#ruby
#ruby
Вопрос:
Я понимаю, что x |= y
это в основном означает x = x|y
. Оператор |
определен для класса Set
как вычисляющий объединение двух множеств. Действительно, мы можем видеть:
require 'set'
r = Set.new(%w(a b));
s = Set.new(%w(c d));
r |= s; # r => #<Set: {"a", "b", "c", "d"}>
Но посмотрите, например, следующее определение класса:
class Demo;
def initialize(s);
@x = s.dup;
end;
attr_accessor :x;
def m!(t);
x |= t.x; ' <--- HERE TROUBLE!
end;
завершение
Я использую этот класс следующим образом:
u = Demo.new(Set.new(%w(a b)))
v = Demo.new(Set.new(%w(c d)))
u.m!(v)
Если я сейчас посмотрю на u.x, я увижу, что он по-прежнему содержит множество a,b, а не a,b,c,d. Мне кажется, что это связано с тем, что я использую средство доступа к атрибутам, в частности метод setter . Если бы я написал @x |= t.x
, это сработало бы. Может ли быть так, что левая часть x |= t.x
использует получатель x
, а не установщик x=
, тем самым создавая объединение во временном объекте Set?
Кстати, я использую довольно старую версию Ruby (JRuby 1.7.x, примерно соответствующую языковой версии Ruby 1.9.3).
Комментарии:
1. Альтернативно:
x.merge(t.x)
который добавляет элементы изt.x
вx
. (без создания нового набора)
Ответ №1:
Причина этого в том, что в
x = 3
x
всегда интерпретируется как локальная переменная, прежде чем ruby начнет поиск метода x=
. Это означает, что ваш метод преобразуется в:
def m!(t)
x = nil # local variable initialization
x = x | t.x
end;
Чтобы решить эту проблему, вам необходимо использовать явный self
принудительный вызов метода:
def m!(t);
self.x |= t.x
end
Еще одно замечание — пожалуйста, не используйте точки с запятой в ruby. Есть только очень редкие ситуации, в которых они нуждались, но мы обычно их избегаем
Комментарии:
1. Из документации : «При использовании назначения метода у вас всегда должен быть приемник. Если у вас нет получателя, Ruby предполагает, что вы присваиваете локальной переменной »