Да, см. следующее из Строковые ресурсы: форматирование и стилизация
Если вам нужно отформатировать строки, используя
String.format(String, Object...)
, тогда вы можете сделать это, поместив аргументы формата в ресурс строки. Например, со следующим ресурсом:
Hello, %1$s! You have %2$d new messages. В этом примере строка формата имеет два аргумента:
%1$s
- это строка, а%2$d
- десятичное число. Вы можете отформатировать строку с аргументами из вашего приложения следующим образом:blockquote>Resources res = getResources(); String text = String.format(res.getString(R.string.welcome_messages), username, mailCount);
Основное использование
Обратите внимание, что
getString
имеет перегрузку, которая использует эту строку как format:String text = res.getString(R.string.welcome_messages, username, mailCount);
Plurals
Если вам нужно обрабатывать множественные числа, используйте это:
- Hello, %1$s! You have a new message.
- Hello, %1$s! You have %2$d new messages.
Первый параметр
mailCount
используется для решить, какой формат использовать (одно или несколько), другими параметрами являются ваши подстановки:Resources res = getResources(); String text = res.getQuantityString(R.plurals.welcome_messages, mailCount, username, mailCount);
Подробнее см. в String Resources: Plurals .
Если Вы eval
луг строка, отправленная, или модифицируемые пользователем, это эквивалентно разрешению выполнения произвольного кода. Вообразите, содержала ли строка вызов ОС к rm -rf /
или подобный. Тем не менее в ситуациях, где Вы знаете, строки соответственно ограничиваются, или Ваш интерпретатор Ruby поигрался в песочнице соответственно, или идеально оба, eval
могут быть чрезвычайно мощными.
проблема походит Внедрение SQL , если Вы знакомы. Решение здесь аналогично решению инжекционной проблемы (параметризированные запросы). Таким образом, если операторы, которые Вы хотели бы к eval
, как известно, имеют очень определенную форму, а не весь из оператора должны быть отправленным пользователем, только несколькими переменными, математическим выражением, или подобный, можно взять в этих маленьких частях от пользователя, санировать их при необходимости, затем оценить безопасный шаблонный оператор с вводом данных пользователем, включенным в соответствующих местах.
eval
не только небезопасен (как уже указывалось в другом месте), он также медленный. Каждый раз, когда он выполняется, AST кода eval
необходимо заново анализировать (и, например, для JRuby, превращенного в байт-код), что является строковой операцией и, вероятно, также плохо для локальности кэша (в предположении что работающей программы не много eval
, и соответствующие части интерпретатора, таким образом, кешируются, помимо того, что они большие).
Почему в Ruby вообще есть eval
, спросите вы? В основном «потому что мы можем» - фактически, когда было изобретено eval
(для языка программирования LISP), это было в основном для шоу ! Более того, использование eval
- это правильная вещь, когда вы хотите «добавить интерпретатор в ваш интерпретатор» для таких задач метапрограммирования, как написание препроцессора, отладчика или шаблонизатора. Общая идея для таких приложений состоит в том, чтобы помассировать некоторый код Ruby и вызвать eval
для него, и это, безусловно, лучше, чем переосмысление и реализация предметно-ориентированного игрушечного языка, ловушка, также известная как Десятое правило Гринспуна . Предостережения: остерегайтесь затрат, например, для движка шаблонов, делайте все свои работы во время запуска, а не во время работы; и не eval
не доверяйте коду, если вы не знаете, как его «приручить», то есть выберите и примените безопасное подмножество языка в соответствии с теорией дисциплины способностей . Последний - это много действительно трудной работы (см., Например, , как это было сделано для Java ; я не знаю о таких усилиях для Ruby, к сожалению).
В Ruby есть несколько уловок, которые могут быть более подходящими, чем eval()
:
#send
, который позволяет вам вызывать метод, имя которого у вас есть в виде строки, и передавать параметры в она. yield
позволяет передавать блок кода методу, который будет выполняться в контексте метода получения. Kernel.const_get("String")
достаточно, чтобы получить класс, имя которого у вас есть в виде строки. Я думаю, что я не могу объяснить их должным образом подробно, поэтому я просто дал вам подсказки, если вы заинтересованы, вы будете Google.
Это затрудняет отладку. Это затрудняет оптимизацию. Но, прежде всего, обычно это признак того, что есть лучший способ сделать то, что вы пытаетесь сделать.
Если вы расскажете нам, чего вы пытаетесь достичь с помощью eval
, вы можете получить более релевантные ответы, относящиеся к вашему конкретному сценарию.
Оценка является невероятно мощной функцией, которая должна быть использована тщательно. Помимо проблем безопасности, на которые указывает Матовый J, Вы также найдете, что отладка оцененного кода времени выполнения является чрезвычайно трудной. Проблема в оцененном блоке кода времени выполнения будет трудной для интерпретатора выразить - настолько ищущий, это будет трудно.
Однако если Вы довольны той проблемой и не обеспокоены проблемой безопасности, тогда Вы не должны избегать использования одной из функций, которая делает рубин как обращающийся как есть
В определенных ситуациях удачное расположение eval
является умным и уменьшает количество требуемого кода. В дополнение к проблемам безопасности, которые были упомянуты Мэттом J, вам также нужно задать себе один очень простой вопрос:
Когда все это сказано и сделано, может ли кто-нибудь еще прочесть ваш код и понять, что вы сделали?
Если ответ отрицательный, то то, что вы получили с eval
, забывается для удобства обслуживания. Эта проблема не только применима, если вы работаете в команде, но также применима и к вам - вы хотите иметь возможность оглянуться назад на свои месяцы кода, если не годы, и знать, что вы сделали.
Если вы передаете что-либо, что вы получаете «извне», eval
, вы делаете что-то не так, и это очень неприятно. очень трудно избежать кода, достаточного для того, чтобы он был безопасным, поэтому я считаю его довольно небезопасным. Тем не менее, если вы используете eval для избежания дублирования или других подобных вещей, как в следующем примере кода, можно использовать его.
class Foo
def self.define_getters(*symbols)
symbols.each do |symbol|
eval "def #{symbol}; @#{symbol}; end"
end
end
define_getters :foo, :bar, :baz
end
Однако, по крайней мере в Ruby 1.9.1, в Ruby есть действительно мощные методы метапрограммирования, и вы могли бы вместо этого сделать следующее:
class Foo
def self.define_getters(*symbols)
symbols.each do |symbol|
define_method(symbol) { instance_variable_get(symbol) }
end
end
define_getters :foo, :bar, :baz
end
Для большинства целей вы хотите использовать эти методы, и не нужно убегать.
Другая плохая вещь в eval
заключается в том, что (по крайней мере, в Ruby) он довольно медленный, поскольку интерпретатору необходимо проанализировать строку и затем выполнить код внутри текущей привязки. Другие методы вызывают функцию C напрямую, и поэтому вы должны получить значительное ускорение.