2015-03-06 4 views
3

Я просматриваю вопросы в Ruby Prep от App Academy, и я хочу знать, почему это решение работает. Похоже, что массив слов никогда не изменяется, но метод работает. Это глюк в матрице, или это прямо под моим носом?Заглавные слова в массиве Ruby

def capitalize_words(string) 
    words = string.split(" ") 

    idx = 0 
    while idx < words.length 
    word = words[idx] 
    word[0] = word[0].upcase 
    idx += 1 
    end 

    return words.join(" ") 
end 
+1

Сообщения соответствующего код – August

+0

Опубликован, жаль, что это мой первый пост и форматирование взяли момент. @August –

ответ

1

String#[]= - мутирующая операция. Для иллюстрации использования краткого, содержащийся отрывка из кода:

word = "foo" 
word[0] = word[0].upcase # <-- verbatim from your code 
word #=> "Foo" 

word еще точно такой же объект, содержащийся в массиве words (массивах просто содержат ссылки на объекты, а не данные в них), но это было мутировал на месте. Обычно лучше избегать мутаций, когда это возможно, поскольку это делает неочевидным то, что происходит (как вы можете видеть).

Ваш код может также быть более сжато написан с использованием map & capitalize (и без каких-либо мутаций):

string.split(' ').map(&:capitalize).join(' ') 
+1

Забудьте об этом, я не могу сказать, что я пытаюсь сказать в этом комментарии. -_- –

0

word = word[idx] создает копию ваших данных. Затем он изменит эту копию вместо слов в исходном массиве.

Простое решение будет:

def capitalize_words(string) 
    words = string.split(" ") 

    idx = 0 
    while idx < words.length 
    words[idx][0] = words[idx][0].upcase 
    idx += 1 
    end 

    return words.join(" ") 
end 
2

метод работает, потому что word содержит ссылку на позицию массива. Поэтому, когда вы назначаете:

word = words[idx] 

Вы просто используете word как сокращение для работы на этом элементе массива, который получает модифицирована:

word[0] = word[0].upcase 

-

Кроме того, если «Мне хотелось бы вернуться к этому ответу после изучения Ruby, вот упрощенная версия метода:

def capitalize_words(string) 
    string.split.map(&:capitalize).join(' ') 
end 
+0

Это ... действительно странно. Я бы подумал, что мне нужно будет установить слова [idx] = word. Это рубин-специфическая вещь или что? Есть ли имя для этого, чтобы я мог изучить его немного больше? –

+0

@Styx_ Это называется * мутация *. Как указано в моем ответе, массивы просто содержат ссылки на объекты, поэтому, когда вы мутируете объект, он «меняется» везде, где есть ссылка на него. Если вы вызываете 'freeeze' на объект в Ruby, он не может быть изменен. Почти каждый язык (к сожалению) связан с мутацией, сохраните [Clojure] (https://en.wikipedia.org/wiki/Clojure). –