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

Как программисты Ruby выполняют проверку типов?

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

4b9b3361

Ответ 1

Ruby, конечно, динамически типизирован.

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

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

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

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

Ответ 2

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

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' bug. Something unexpected happened: #{$!.message}"
end

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

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