Рубиновое присваивание внутри итератора - PullRequest
0 голосов
/ 19 октября 2010

Я хочу преобразовать имя «Джон Доу-Смит» в «Джон Доу-Смит», используя код:

name = "JOHN DOE-SMITH"  
name_split = name.split(/\s/)  
name_split.each do |x|  
  if x =~ /-/  
    name1, name2 = x.split(/-/)  
    x = name1.capitalize + "-" + name2.capitalize  
  else  
    x.capitalize!  
  end  
end  
puts name_split.join(" ")  

Результат - неожиданный «Джон Доу-Смит»
Почему x.capitalize! иметь эффект, пока x = "foo" не имеет?
Есть ли лучший способ сделать это?

Ответы [ 3 ]

1 голос
/ 19 октября 2010

x = "foo" просто присваивает переменную x для ссылки на другой объект. Поскольку эта переменная существует только в блоке, это не имеет наблюдаемого эффекта. Это не меняет строку вообще. x.capitalize!, с другой стороны, отправляет сообщение capitalize! в строку, что приводит к изменению регистра.

0 голосов
/ 19 октября 2010

Как насчет

cap_name = name.split.map{|w| w.split("-").map(&:capitalize).join("-") }.join(" ")
0 голосов
/ 19 октября 2010

Потому что x - это локальная переменная, которая указывает на строку, использующую те же данные. Вот почему влияние на новое значение не изменяется внутри строки.

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

name_split = name.split(/\s/).map do |x|
  if x =~ /-/
    name1, name2 = x.split(/-/)
    name1.capitalize + "-" + name2.capitalize
  else
    x.capitalize
  end
end  
puts name_split.join(" ")

Или, если вы найдете это более читабельным:

name_split = name.split(/\s/).map do |x|
  x.split(/-/).map(&:capitalize).join('-')
end
puts name_split.join(" ")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...