Почему вызов этих двух методов .map не дает эквивалентных результатов? Первый работает должным образом, а второй не действует.

array = ["batman","boobytrap"]

puts array.map { |x| x.reverse! }
=> namtab
=> partyboob

puts array.map { |x| x = x.reverse }
=> batman
=> boobytrap
1
Reverse Engineered 8 Сен 2016 в 10:37

4 ответа

Когда вы выполняете array.map { |x| x.reverse! }, он меняет значения массива.

array = ["batman","boobytrap"]

puts array.map { |x| x.reverse! }
=> namtab
=> partyboob

array
=> ["namtab", "partyboob"]

Если вы выполните вторую операцию с тем же массивом, она даст те же результаты, что и вы указали в вопросе. Однако это не изменит значение исходного массива.

array = ["batman","boobytrap"]

puts array.map { |x| x.reverse! }
=> namtab
=> partyboob

array
=> ["namtab", "partyboob"]

puts array.map { |x| x = x.reverse }
=> batman
=> boobytrap

array
=> ["namtab", "partyboob"]

Чтобы изменить значение исходного массива, используйте map! во второй операции.

array = ["batman","boobytrap"]

puts array.map { |x| x.reverse! }
=> namtab
=> partyboob

array
=> ["namtab", "partyboob"]

puts array.map! { |x| x.reverse }
=> batman
=> boobytrap

array
=> ["batman", "boobytrap"]
1
Pramod 8 Сен 2016 в 09:35

Напечатайте array после puts array.map { |x| x.reverse! }. Вы увидите - массив изменился. Прочтите документацию для reverse! метод.

1
Flamine 8 Сен 2016 в 08:56

Вы должны изменить свое представление о том, что это за переменная. Переменная не является фактическим значением, а только ссылкой на это значение.

array = ["batman"]

# We are freezing this string to prevent ruby from creating a
# new object for a string with the same value.
# This isnt really necessary, just to "make sure" the memory
# address stays the same.
string = "boobytrap".freeze

array.each do |val|
  puts "before: ",
       "val.object_id: #{val.object_id}",
       "string.object_id: #{string.object_id}",
       "array[0].object_id: #{array[0].object_id}",
       ""

  val = string

  puts "after: ",
       "val.object_id: #{val.object_id}",
       "string.object_id: #{string.object_id}",
       "array[0].object_id: #{array[0].object_id}"
end

# before:
# val.object_id: 70244773377800,
# string.object_id: 70244761504360,
# array[0].object_id: 70244773377800
#
# after:
# val.object_id: 70244761504360,
# string.object_id: 70244761504360,
# array[0].object_id: 70244773377800

Очевидно, что значения будут отличаться, если вы запустите этот код на своем компьютере, но дело в том, что адрес памяти для val изменится, а array[0] (откуда происходит val) останется прежним после того, как мы присвоили строка в val. Итак, в основном, что мы делаем с переназначением, мы говорим ruby, что значение val больше не находится в 70244773377800, а в 70244761504360. Тем не менее, массив по-прежнему ссылается на свое первое значение с 70244773377800!

С другой стороны, вызов метода #reverse!, который вы используете в своем примере для x, изменяет значение всего, что находится в памяти по адресу 70244773377800, поэтому он работает так, как вы ожидали.

TL; DR; Ваш первый пример изменяет значение в памяти, а второй пример назначает новый адрес памяти локальной переменной.

1
Ninigi 8 Сен 2016 в 09:18

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

irb:001:0> array = ["batman","boobytrap"]
=> ["batman", "boobytrap"]
irb:002:0> puts array.map { |x| x.reverse! }
namtab
partyboob
=> nil
irb:003:0> array
=> ["namtab", "partyboob"]

Итак, во второй раз выполняется то, что вы ожидаете, но входные данные не такие, как вы думаете. Если вы попробуете второй случай автономно, не выполняя первый, вы увидите, что он работает так, как вы ожидали.

1
Ginty 8 Сен 2016 в 09:06