Я так понимаю.[String.new] * 3
создает , а не создает три String
объекта.Он создает one и создает трехэлементный массив, в котором каждый элемент указывает на один и тот же объект.
Причина, по которой вы не видите "поврежденную строку", заключается в том, что у вас есть a
присвоено новое значение.Таким образом, после строки a = "hi"
, a
ссылается на новый объект String
("hi"), в то время как b
и c
все еще ссылаются на тот же исходный объект ("").
То же самое происходит с [Hash.new] * 3
;но на этот раз вы не назначаете никаких переменных.Скорее, вы изменяете один Hash
объект, добавляя ключ / значение [hi, :test]
(через a['hi'] = :test
).На этом этапе вы изменили один объект, на который ссылаются a
, b
и c
.
Вот пример искусственного кода, чтобы сделать это более конкретным:
class Thing
attr_accessor :value
def initialize(value)
@value = value
end
end
# a, b, and c all refer to the same Thing object
a, b, c = [Thing.new(0)] * 3
# Here we *modify* that object
a.value = 5
# Verify b refers to the same object as a -- outputs "5"
puts b.value
# Now *assign* a to a NEW Thing object
a = Thing.new(10)
# Verify a and b now refer to different objects -- outputs "10, 5"
puts "#{a.value}, #{b.value}"
Имеет ли это смысл?
Обновление : я не гуру по Ruby, так что может быть более здравый способ сделать это.Но если вы хотите иметь возможность использовать синтаксис, похожий на умножение, для инициализации массива с множеством различных объектов, вы можете рассмотреть этот подход: создать массив из lambdas , а затем вызвать их все, используя map
.
Вот что я имею в виду:
def call_all(lambdas)
lambdas.map{ |f| f.call }
end
a, b, c = call_all([lambda{Hash.new}] * 3)
Вы можете убедиться, что этот подход работает довольно легко:
x, y, z = call_all([lambda{rand(100)}] * 3)
# This should output 3 random (probably different) numbers
puts "#{x}, #{y}, #{z}"
Обновление 2 : мне нравится подход numbers1311407, использующий Array#new
намного лучше.