4 ответов:
TL; DR
простое эмпирическое правило заключается в использовании символов каждый раз, когда вы нужны внутренние идентификаторы. Для Ruby
ответ
единственная причина не использовать их идентификаторы, которые генерируются динамически из-за проблем с памятью.
этот вопрос очень распространен, потому что многие языки программирования не имеют символов, только строки и, следовательно, строки также используются в качестве идентификаторов в коде. Вы должны беспокоиться о том, какие символы должно быть не только когда вы должны использовать символы. Символы должны быть идентификаторами. Если вы будете следовать этой философии, скорее всего, вы будете делать все правильно.
Существует несколько различий между внедрением символов и строк. Самое главное в символах-это то, что они неизменяемые. Это означает, что они будут их ценность никогда не менялась. Из-за этого, символы создаются быстрее, чем строки и некоторые операции, такие как сравнение двух символов также быстрее.
тот факт, что символ является неизменным, позволяет Ruby использовать один и тот же объект каждый раз, когда вы ссылаетесь на символ, экономя память. Поэтому каждый раз, когда переводчик читает
:my_keyон может взять его из памяти, а не создавать его снова. Это дешевле, чем инициализация новой строки каждый раз.вы можете получить список всех символов, которые уже созданы с помощью команды
Symbol.all_symbols:symbols_count = Symbol.all_symbols.count # all_symbols is an array with all # instantiated symbols. a = :one puts a.object_id # prints 167778 a = :two puts a.object_id # prints 167858 a = :one puts a.object_id # prints 167778 again - the same object_id from the first time! puts Symbol.all_symbols.count - symbols_count # prints 2, the two objects we created.для версий Ruby до 2.2, как только символ будет создан, эта память будет никогда не быть свободным снова. Единственный способ освободить память-это перезапустить приложение. Таким образом, символы также являются основной причиной утечек памяти при неправильном использовании. Самый простой способ создать утечку памяти - это использовать метод
to_symна входных данных пользователя, так как эти данные всегда будут меняться, новая часть память будет использоваться навсегда в экземпляре программного обеспечения. Рубин 2.2 представил символ сборщик мусора, который освобождает символы, генерируемые динамически, поэтому утечки памяти, генерируемые путем динамического создания символов, больше не вызывают беспокойства.отвечая на ваш вопрос:
правда ли, что я должен использовать символ вместо строки, если в моем приложении или скрипте есть хотя бы две одинаковые строки?
если что вы ищете идентификатор, который будет использоваться внутри вашего кода, Вы должны использовать символы. Если вы печатаете вывод, вы должны идти со строками, даже если он появляется несколько раз, даже выделяя два разных объекта в памяти.
Вот рассуждения:
- печать символов будет медленнее, чем печать строк, потому что они приведены к строкам.
- наличие большого количества различных символов увеличит общее использование памяти ваше приложение, так как они никогда не освобождаются. И вы никогда не используете все строки из вашего кода одновременно.
Use case by @AlanDert
@AlanDert: если я использую много раз что-то вроде %input{type:: checkbox} в коде haml, что я должен использовать в качестве флажка?
Я: Да.
@AlanDert: но чтобы распечатать символ на html-странице, он должен быть преобразован в строку, не так ли? какой смысл его использовать тогда?
каков тип входного сигнала? Идентификатор типа ввода, который вы хотите использовать, или что-то, что вы хотите показать пользователю?
это правда, что в какой - то момент он станет HTML-кодом, но в тот момент, когда вы пишете эту строку своего кода, это означает, что это идентификатор-он определяет, какое поле ввода вам нужно. Таким образом, он используется снова и снова в вашем коде и всегда имеет одну и ту же "строку" символов в качестве идентификатора и не будет создать утечку памяти.
тем не менее, почему бы нам не оценить данные, чтобы увидеть, если строки быстрее?
это простой тест, который я создал для этого:
require 'benchmark' require 'haml' str = Benchmark.measure do 10_000.times do Haml::Engine.new('%input{type: "checkbox"}').render end end.total sym = Benchmark.measure do 10_000.times do Haml::Engine.new('%input{type: :checkbox}').render end end.total puts "String: " + str.to_s puts "Symbol: " + sym.to_sтри выхода:
# first time String: 5.14 Symbol: 5.07 #second String: 5.29 Symbol: 5.050000000000001 #third String: 4.7700000000000005 Symbol: 4.68таким образом, использование smbols на самом деле немного быстрее, чем использование строк. Почему? Это зависит от того, как реализуется HAML. Мне нужно было бы немного взломать код HAML, чтобы увидеть, но если вы продолжаете использовать символы в концепции идентификатора, ваше приложение будет быстрее и надежнее. Когда возникают вопросы, проверьте их и получите ответы.
проще говоря, символ-это имя, состоящее из символов, но неизменным. Строка, напротив, является упорядоченным контейнером для символов, содержимое которого может изменяться.
- символ Рубина-это объект с O (1) сравнением
чтобы сравнить две строки, нам потенциально нужно посмотреть на каждый символ. Для двух строк длины N это потребует N + 1 сравнения(которые компьютерные ученые называют "o (N) time").
def string_comp str1, str2 return false if str1.length != str2.length for i in 0...str1.length return false if str1[i] != str2[i] end return true end string_comp "foo", "foo"но так как каждый внешний вид :foo относится к одному и тому же объекту, мы можем сравнить символы, глядя на идентификаторы объектов. Мы можем сделать это с помощью одного сравнения (на которое ссылаются компьютерные ученые как "O(1) времени").
def symbol_comp sym1, sym2 sym1.object_id == sym2.object_id end symbol_comp :foo, :foo
- символ Рубина-это метка в свободной форме перечисления
В C++ мы можем использовать "перечисления" для представления семейств связанных констант:
enum BugStatus { OPEN, CLOSED }; BugStatus original_status = OPEN; BugStatus current_status = CLOSED;но поскольку Ruby является динамическим языком, мы не беспокоимся об объявлении типа BugStatus или отслеживании юридических значений. Вместо этого мы представляем значения перечисления в виде символов:
original_status = :open current_status = :closed3.Символ Рубина-это константа, уникальная имя
в Ruby мы можем изменить содержимое строки:
"foo"[0] = ?b # "boo"но мы не можем изменить содержание символа:
:foo[0] = ?b # Raises an error
- символ Рубина-это ключевое слово для ключевого аргумента
при передаче аргументов ключевых слов в функцию Ruby мы задаем ключевые слова с помощью символов:
# Build a URL for 'bug' using Rails. url_for :controller => 'bug', :action => 'show', :id => bug.id
- символ Рубина является отличным выбором для хэш-ключа
как правило, мы будем использовать символы для представления ключей хэш-таблицы:
options = {} options[:auto_save] = true options[:show_comments] = false
вот хороший тест strings vs symbols, который я нашел в codecademy:
require 'benchmark' string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)] symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)] string_time = Benchmark.realtime do 1000_000.times { string_AZ["r"] } end symbol_time = Benchmark.realtime do 1000_000.times { symbol_AZ[:r] } end puts "String time: #{string_time} seconds." puts "Symbol time: #{symbol_time} seconds."выход:
String time: 0.21983 seconds. Symbol time: 0.087873 seconds.
Comments