Существует ли метод Ruby для определения, равны ли все переменные экземпляра двух экземпляров одного и того же класса? - PullRequest
0 голосов
/ 21 января 2020

Существует ли метод Ruby для сравнения двух объектов на основе того, равны ли все их переменные экземпляра? Метод будет вести себя как этот код.

class Coordinates
  attr_reader :x, :y
  def initialize(x, y)
    @x = x
    @y = y
  end
end

coordinates1 = Coordinates.new(0, 0)
coordinates2 = Coordinates.new(0, 0)
coordinates3 = Coordinates.new(1, 0)

compare(coordinates1, coordinates1) # => true
compare(coordinates1, coordinates2) # => true
compare(coordinates1, coordinates3) # => false

Существует ли этот метод или что-то подобное?

Если это плохой вопрос, скажите, пожалуйста, почему конструктивно. Я получил несколько отрицательных ответов на мой предыдущий вопрос, но у меня нет причин, почему.

Большое спасибо за помощь.

Олав

Ответы [ 2 ]

5 голосов
/ 21 января 2020

Для этого нет встроенного метода, но вы могли бы его легко написать. Тем не менее, я думаю, что вы задаете вопрос XY.

Вот что я думаю, что вопрос должен сказать:

Как мне определить метод для проверки этих двух Coordinates экземпляров равны?

И вот мой ответ:

Определить пользовательский == метод:

class Coordinates
  attr_reader :x, :y
  def initialize(x, y)
    @x = x
    @y = y
  end

  def ==(other)
    return super unless other.is_a?(Coordinates)

    x == other.x && y == other.y
  end
end

... Но в духе StackOverflow, вот несколько метапрограмм, чтобы проверить, имеют ли все переменные экземпляра одинаковые имя и значение:

# returns true if all objects have the same instance variable names and values
def compare(*objects)
  objects.map do |object|
    object.instance_variables.map do |var_name|
      [var_name, object.instance_variable_get(var_name)]
    end
  end.uniq.count == 1
end
2 голосов
/ 21 января 2020

Дело 1

class A
  def initialize(x,y)
    @x = x
    @y = y
  end
  def m
    @x = 5
    @y = 6
  end
end

a1 = A.new(1,2)
   #=> #<A:0x00005d22a3878048 @x=1, @y=2> 
a1.m
a1 #=> #<A:0x00005d22a3878048 @x=5, @y=6> 

a2 = A.new(3,4)
   #=> #<A:0x00005d22a38b5330 @x=3, @y=4> 
a2.m
a2 #=> #<A:0x00005d22a38b5330 @x=5, @y=6> 

Затем

a1.instance_variables.all? { |e|
  a1.instance_variable_get(e) == a2.instance_variable_get(e) }
  #=> true

говорит нам, что значения @x и значения @y одинаковы для обоих экземпляров.

Случай 2

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

class A
  def initialize(x,y)
    @x = x
    @y = y
  end
  def m
    @z = 3 if @x == 3
    @x = 5
    @y = 6
  end
end

a1 = A.new(1,2)
   #=> #<A:0x000057d1fd563c78 @x=1, @y=2> 
a1.m
a1 #=> #<A:0x000057d1fd27f200 @x=5, @y=6> 

a2 = A.new(3,4)
   #=> #<A:0x000057d1fd57cb38 @x=3, @y=4>
a2.m
a2 #=> #<A:0x000057d1fd2f9e10 @x=5, @y=6, @z=3> 

В этот момент все переменные экземпляра одного из этих экземпляров равны соответствующей переменной экземпляра другого экземпляра? Нет, потому что a2 имеет дополнительную переменную экземпляра, @z. Поэтому

a1.instance_variables.all? { |e|
  a1.instance_variable_get(e) == a2.instance_variable_get(e) }
  #=> true

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

a1.instance_variables.all? { |e|
  a1.instance_variable_get(e) == a2.instance_variable_get(e) } &&
a2.instance_variables.all? { |e|
  a1.instance_variable_get(e) == a2.instance_variable_get(e) } 
 #=> true && false => false

Это имеет значение, однако, если @z равно nil.

Случай 3

class A
  def initialize(x,y)
    @x = x
    @y = y
  end
  def m
    @z = nil if @x == 3
    @x = 5
    @y = 6
  end
end

a1 = A.new(1,2)
   #=> #<A:0x000057d1fd2d18e8 @x=1, @y=2> 
a1.m
a1 #=> #<A:0x000057d1fd2d18e8 @x=5, @y=6> 

a2 = A.new(3,4)
  #=> #<A:0x000057d1fd46b460 @x=3, @y=4> 
a2.m
a2
  #=> #<A:0x000057d1fd46b460 @x=5, @y=6, @z=nil> 

a1.instance_variables.all? { |e|
  a1.instance_variable_get(e) == a2.instance_variable_get(e) } &&
a2.instance_variables.all? { |e|
  a1.instance_variable_get(e) == a2.instance_variable_get(e) }
  #=> true && true => true

Мы получаем этот неверный результат, потому что:

class A
end

A.new.instance_variable_get(:@z)
  #=> nil

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

(a1.instance_variables.sort == a2.instance_variables.sort) &&
a1.instance_variables.all? { |e|
  a1.instance_variable_get(e) == a2.instance_variable_get(e) }    
  #=> false && true => false

См. Enumerable # all? , Object # instance_variables и Object # instance_variable_get .

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