Подтвердить что ты не робот

Почему не рекомендуется динамически создавать множество символов в рубине?

Какова функция символа в рубине? какая разница между строкой и символом? Почему не рекомендуется динамически создавать множество символов?

4b9b3361

Ответ 1

Символы похожи на строки, но они неизменяемы - они не могут быть изменены.

Они только помещаются в память один раз, что делает их очень эффективными для использования таких вещей, как ключи в хэшах, но они остаются в памяти до тех пор, пока программа не выйдет. Это делает их памятью, если вы их неправильно используете.

Если вы динамически создаете множество символов, вы выделяете много памяти, которая не может быть освобождена до завершения вашей программы. Вы должны динамически создавать символы (используя string.to_sym), если вы знаете, что:

  • необходимо повторно обращаться к символу
  • не нужно их изменять

Как я уже говорил ранее, они полезны для таких вещей, как хэши, где вам больше нужна идентификация переменной, чем ее значение. Символы, когда они правильно используются, являются читаемым и эффективным способом передачи идентичности.

Я объясню, что я имею в виду о неизменности символов RE ваш комментарий.

Строки похожи на массивы; они могут быть изменены на месте:

12:17:44 ~$ irb
irb(main):001:0> string = "Hello World!"
=> "Hello World!"
irb(main):002:0> string[5] = 'z'
=> "z"
irb(main):003:0> string
=> "HellozWorld!"
irb(main):004:0> 

Символы больше похожи на числа; они не могут быть отредактированы на месте:

irb(main):011:0> symbol = :Hello_World
=> :Hello_World
irb(main):012:0> symbol[5] = 'z'
NoMethodError: undefined method `[]=' for :Hello_World:Symbol
    from (irb):12
    from :0

Ответ 2

Символ является одним и тем же объектом и тем же распределением памяти независимо от того, где он используется:

>> :hello.object_id
=> 331068
>> a = :hello
=> :hello
>> a.object_id
=> 331068
>> b = :hello
=> :hello
>> b.object_id
=> 331068
>> a = "hello"
=> "hello"
>> a.object_id
=> 2149256980
>> b = "hello"
=> "hello"
>> b.object_id
=> 2149235120
>> b = "hell" + "o"

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

Таким образом, символы могут быть полезны для уменьшения накладных расходов памяти. Однако - это утечка памяти, ожидающая своего появления, потому что символы не могут быть собраны после сборки. Создание тысяч и тысяч символов будет выделять память и не восстанавливаться. Хлоп!

Ответ 3

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

Плохое (символ создается независимо от пользовательского ввода):

name = params[:name].to_sym

Хорошо (символ создается только в том случае, если пользовательский ввод разрешен):

whitelist = ['allowed_value', 'another_allowed_value']
raise ArgumentError unless whitelist.include?(params[:name])
name = params[:name].to_sym

Ответ 4

Если вы используете Ruby 2.2.0 или новее, обычно должно быть нормально динамически создавать множество символов, потому что они будут собирать мусор в соответствии с Объявление Ruby 2.2.0-preview1, в котором есть ссылка на подробнее о новом символе GC. Однако, если вы передаете свои динамические символы на какой-то код, который преобразует его в ID (внутренняя концепция реализации Ruby, используемая в исходном коде C), тогда в этом случае он будет закреплен и никогда не получит сбор мусора. Я не уверен, как обычно это происходит.

Вы можете думать о символах как о чем-то, а строки (грубо говоря) как о последовательности символов. Во многих случаях вы можете использовать либо символ, либо строку, либо вы можете использовать смесь из двух. Символы неизменны, что означает, что они не могут быть изменены после создания. Символы пути реализованы, очень эффективно сравнивать два символа, чтобы убедиться, что они равны, поэтому их использование в качестве ключей к хэшам должно быть немного быстрее, чем использование строк. Символы не имеют большого количества методов, которые выполняют строки, например start_with?, поэтому вам нужно будет использовать to_s для преобразования символа в строку перед вызовом этих методов.

Подробнее о символах можно прочитать в документации:

http://www.ruby-doc.org/core-2.1.3/Symbol.html