Почему не стоит динамически создавать много символов в ruby? - PullRequest
61 голосов
/ 01 января 2011

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

Ответы [ 5 ]

88 голосов
/ 01 января 2011

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

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

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

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

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

Я объясню, что я имею в виду относительно неизменности символов, 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
9 голосов
/ 01 января 2011

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

>> :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"

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

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

6 голосов
/ 13 июня 2013

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

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

name = params[:name].to_sym

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

whitelist = ['allowed_value', 'another_allowed_value']
raise ArgumentError unless whitelist.include?(params[:name])
name = params[:name].to_sym
2 голосов
/ 06 мая 2016

Начиная с Ruby 2.2 и выше Символы автоматически удаляются сборщиком мусора, поэтому это не должно быть проблемой.

2 голосов
/ 25 сентября 2014

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

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

Вы можете прочитать больше оСимволы здесь в документации:

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

...