Как программисты Ruby выполняют проверку типов? - PullRequest
21 голосов
/ 22 марта 2012

Поскольку в ruby ​​нет типа, как программисты на Ruby гарантируют, что функция получает правильные аргументы?Прямо сейчас я повторяю операторы if object.kind_of / instance_of, чтобы проверять и вызывать ошибки во время выполнения везде, что ужасно.Должен быть лучший способ сделать это.

Ответы [ 5 ]

20 голосов
/ 22 марта 2012

Мой личный способ, который я не уверен, если это вообще рекомендуемый способ, - это проверять тип и делать другие проверки при возникновении ошибки.Я положил процедуру проверки типа в блоке спасения.Таким образом, я могу избежать потери производительности, когда заданы правильные аргументы, но по-прежнему возвращать правильное сообщение об ошибке при возникновении ошибки.

def foo arg1, arg2, arg3
  ...
  main_routine
  ...
rescue
  ## check for type and other validations
  raise "Expecting an array: #{arg1.inspect}" unless arg1.kind_of?(Array)
  raise "The first argument must be of length 2: #{arg1.inspect}" unless arg1.length == 2
  raise "Expecting a string: #{arg2.inspect}" unless arg2.kind_of?(String)
  raise "The second argument must not be empty" if arg2.empty?
  ...
  raise "This is `foo''s bug. Something unexpected happened: #{$!.message}"
end

Предположим, в main_routine используется метод eachна arg1 при условии, что arg1 является массивом.Если окажется, что это что-то еще, для которого each не определено, то пустое сообщение об ошибке будет выглядеть как method each not defined on ..., что, с точки зрения пользователя метода foo, может быть неполезно.В этом случае исходное сообщение об ошибке будет заменено сообщением Expecting an array: ..., что гораздо полезнее.

18 голосов
/ 22 марта 2012

Ruby, конечно, динамически печатается.

Таким образом метод документации определяет тип контракта; информация о типе перемещается из формальной системы типов в [неформальную спецификацию типа в документации] метода. Я смешиваю общности типа «действует как массив» и такие особенности, как «строка». Звонящий должен ожидать только работу с указанными типами.

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

В свете вышесказанного, я избегаю проверки на определенный тип и избегаю попыток создать перегрузки с таким поведением.

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

9 голосов
/ 22 марта 2012

Если у метода есть причина для существования, он будет вызван.

Если написаны разумные тесты, будет вызвано все.

И если вызывается каждый метод, то каждый методбудет проверяться по типу.

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

1 голос
/ 01 июля 2016

Вы можете использовать Дизайн по контракту подход с контрактами рубиновым камнем. Я нахожу это довольно хорошим.

1 голос
/ 21 декабря 2013

Я рекомендую использовать повышение в начале метода, чтобы добавить ручную проверку типов, просто и эффективно:

def foo(bar)
    raise TypeError, "You called foo without the bar:String needed" unless bar.is_a? String
    bar.upcase
end

Лучший способ, когда у вас мало параметров, также рекомендуется использовать аргументы ключевых слов, доступные на ruby ​​2+, если у вас есть несколько параметров и смотрите подробности текущей / будущей реализации, они улучшают ситуацию, давая Программист способ увидеть, если значение равно нулю.

плюс: вы можете использовать пользовательское исключение

class NotStringError < TypeError
   def message 
     "be creative, use metaprogramming ;)"
#...
raise NotStringError
...