Вот сравнительное сравнение send
против instance_variable_set
:
require 'benchmark'
class Test
VAR_NAME = '@foo'
ATTR_NAME = :foo
attr_accessor ATTR_NAME
def set_by_send i
send("#{ATTR_NAME}=", i)
end
def set_by_instance_variable_set i
instance_variable_set(VAR_NAME, i)
end
end
test = Test.new
Benchmark.bm do |x|
x.report('send ') do
1_000_000.times do |i|
test.set_by_send i
end
end
x.report('instance_variable_set') do
1_000_000.times do |i|
test.set_by_instance_variable_set i
end
end
end
И время:
user system total real
send 1.000000 0.020000 1.020000 ( 1.025247)
instance_variable_set 0.370000 0.000000 0.370000 ( 0.377150)
(измерено с использованием 1.9.2)
Следует отметить, что только в определенных ситуациях (например, в этой, когда средство доступа определено с использованием attr_accessor
), функционально эквивалентны send
и instance_variable_set
.Если есть какая-то логика в задействованном аксессоре, будет разница, и вам придется решить, какой вариант вам нужен из этих двух.instance_variable_set
просто устанавливает ивар, в то время как send
фактически выполняет метод доступа, что бы он ни делал.
Еще одно замечание - оба метода ведут себя по-разному в другом аспекте: если вы instance_variable_set
ивар, который не 'пока не существует, оно будет создано.Если вы вызываете метод доступа, который не существует с помощью send
, возникнет исключение.